{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "- https://course.rs/advance/smart-pointer/intro.html\n",
    "\n",
    "指针就是保存内存地址的变量。Rust 里最常见的是引用 `&T`，本质是“借用”其他变量，零开销。\n",
    "\n",
    "智能指针结构更复杂，附带元数据、长度等信息，可提供额外能力，例如多所有权、自动清理。\n",
    "\n",
    "`String`、`Vec` 等都是智能指针示例：内部既有指向堆内存的指针，也记录长度、容量等。\n",
    "\n",
    "智能指针通常是结构体，关键在实现 `Deref`（像引用一样使用）和 `Drop`（离开作用域自动执行清理）。\n",
    "\n",
    "本章关注三个常用智能指针：\n",
    "\n",
    "- `Box<T>`：把值放到堆上。\n",
    "- `Rc<T>`：引用计数，实现共享所有权。\n",
    "- `Ref<T>` / `RefMut<T>`：通过运行时检查借用规则。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Box<T> 堆对象分配\n",
    "\n",
    "- https://course.rs/advance/smart-pointer/box.html\n",
    "\n",
    "\n",
    "TL;DR\n",
    "- `Box<T>` 把值搬到堆上，只保留一个轻量智能指针在栈上，常用于大数据、需避免拷贝或构造特征对象等场景。\n",
    "- 栈分配快速但容量有限，堆分配灵活；堆上 move 仅复制指针，避免大型数据深拷贝。\n",
    "- 借助 `Box<T>` 可让递归类型、trait 对象等动态大小类型变成编译期可处理的 `Sized`.\n",
    "- `Vec<Box<T>>` 等结构会形成多层指针，使用时需显式解引用（如 `**ptr`）。\n",
    "- `Box::leak` 可把运行期构造的值转成 `'static` 引用，适合全局配置等长期存活数据。\n",
    "- `Box` 背后自动管理堆内存，配合 `Deref`/`Drop` 提供与引用类似的用法和自动清理。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Rust 中的堆栈\n",
    "\n",
    "栈内存连续、容量有限（主线程约 8 MB），函数调用结束即自动清理，分配/回收极快。\n",
    "\n",
    "堆内存碎片化但几乎无限，分配开销更大；Rust 上的堆数据仍受所有权和移动语义约束。\n",
    "\n",
    "所有权转移时，只拷贝栈上的指针/元数据，堆中真实数据无需复制。\n",
    "\n",
    "性能取舍：\n",
    "\n",
    "- 小型数据，在栈上的分配性能和读取性能都要比堆上高\n",
    "- 中型数据，栈上分配性能高，但是读取性能和堆上并无区别，因为无法利用寄存器或 CPU 高速缓存，最终还是要经过一次内存寻址\n",
    "- 大型数据，只建议在堆上分配和使用\n",
    "\n",
    "不要迷信“全栈更快”，根据数据规模与可读性权衡栈与堆的使用。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Hello, world\n"
     ]
    }
   ],
   "source": [
    "{\n",
    "    let b = foo(\"world\"); // 当被从 foo 函数转移给 main 中的 b 变量时，栈上的智能指针被复制一份赋予给 b，而底层数据无需发生改变，这样就完成了所有权从 foo 函数内部到 b 的转移。\n",
    "    println!(\"{}\", b);\n",
    "}\n",
    "\n",
    "fn foo(x: &str) -> String {\n",
    "    let a = \"Hello, \".to_string() + x;\n",
    "    a\n",
    "}"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Box 的使用场景\n",
    "\n",
    "`Box<T>` 把值搬到堆上，智能指针留在栈上，没有额外性能损耗。\n",
    "\n",
    "典型用途：\n",
    "\n",
    "- 主动把数据放堆上（如大块数据、递归结构、trait 对象）。\n",
    "- 避免大型栈数据在所有权转移时的深拷贝。\n",
    "- 将动态大小类型（如递归类型、trait）包装成编译期可知大小的 `Sized`。\n",
    "- 构造 `Box<dyn Trait>` 等特征对象，支持异构集合。\n",
    "\n",
    "常见症状与注意事项：\n",
    "\n",
    "- `println!` 等可借 `Deref` 自动解引用；表达式里需显式 `*`。\n",
    "- 所有权移动只复制指针，不复制堆上内容。\n",
    "- 对 `Vec<Box<T>>` 等多层指针访问时需多次 `*` 转换。\n",
    "\n",
    "总结：需要堆分配但只想付出最低开销时，用 `Box<T>`。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "notebookRunGroups": {
     "groupValue": "1"
    }
   },
   "source": [
    "### 使用 Box<T> 将数据存储在堆上"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "let a = 3; // 变量 a 必然是存储在栈上的"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "a = 3\n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "()"
      ]
     },
     "execution_count": 3,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "{\n",
    "    let a = Box::new(3); // 想要 a 的值存储在堆上就需要使用 Box<T>\n",
    "    println!(\"a = {}\", a); // a = 3, 隐式地调用了 Deref 对智能指针 a 进行了解引用\n",
    "\n",
    "    // 下面一行代码将报错\n",
    "    // let b = a + 1; // cannot add `{integer}` to `Box<{integer}>`\n",
    "}"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [
    {
     "ename": "Error",
     "evalue": "cannot add `{integer}` to `Box<{integer}>`",
     "output_type": "error",
     "traceback": [
      "\u001b[31m[E0369] Error:\u001b[0m cannot add `{integer}` to `Box<{integer}>`",
      "   \u001b[38;5;246m╭\u001b[0m\u001b[38;5;246m─\u001b[0m\u001b[38;5;246m[\u001b[0m command_5:1:1 \u001b[38;5;246m]\u001b[0m",
      "   \u001b[38;5;246m│\u001b[0m",
      " \u001b[38;5;246m5 │\u001b[0m \u001b[38;5;249m \u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249ml\u001b[0m\u001b[38;5;249me\u001b[0m\u001b[38;5;249mt\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249mb\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249m=\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;54ma\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;68m+\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;100m1\u001b[0m\u001b[38;5;249m;\u001b[0m",
      " \u001b[38;5;240m  │\u001b[0m             \u001b[38;5;54m┬\u001b[0m \u001b[38;5;68m┬\u001b[0m \u001b[38;5;100m┬\u001b[0m  ",
      " \u001b[38;5;240m  │\u001b[0m             \u001b[38;5;54m╰\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m Box<{integer}>",
      " \u001b[38;5;240m  │\u001b[0m               \u001b[38;5;68m│\u001b[0m \u001b[38;5;100m│\u001b[0m  ",
      " \u001b[38;5;240m  │\u001b[0m               \u001b[38;5;68m╰\u001b[0m\u001b[38;5;68m─\u001b[0m\u001b[38;5;68m─\u001b[0m\u001b[38;5;68m─\u001b[0m\u001b[38;5;68m─\u001b[0m error: cannot add `{integer}` to `Box<{integer}>`",
      " \u001b[38;5;240m  │\u001b[0m                 \u001b[38;5;100m│\u001b[0m  ",
      " \u001b[38;5;240m  │\u001b[0m                 \u001b[38;5;100m╰\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m {integer}",
      " \u001b[38;5;240m  │\u001b[0m ",
      " \u001b[38;5;240m  │\u001b[0m \u001b[38;5;115mNote\u001b[0m: not implement `Add<{integer}>`",
      "\u001b[38;5;246m───╯\u001b[0m"
     ]
    }
   ],
   "source": [
    "{\n",
    "    let a = Box::new(3);\n",
    "    println!(\"a = {}\", a);\n",
    "\n",
    "    let b = a + 1;\n",
    "}"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "a = 3\n",
      "b = 4\n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "()"
      ]
     },
     "execution_count": 7,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "{\n",
    "    let a = Box::new(3);\n",
    "    println!(\"a = {}\", a);\n",
    "\n",
    "    let b = *a + 1;\n",
    "    println!(\"b = {}\", b);\n",
    "}"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "#### 避免栈上数据的拷贝\n",
    "\n",
    "当栈上数据转移所有权时，实际上是把数据拷贝了一份，最终新旧变量各自拥有不同的数据，因此所有权并未转移。\n",
    "\n",
    "而堆上则不然，底层数据并不会被拷贝，转移所有权仅仅是复制一份栈中的指针，再将新的指针赋予新的变量，然后让拥有旧指针的变量失效，最终完成了所有权的转移："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "1000\n",
      "1000\n",
      "1000\n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "()"
      ]
     },
     "execution_count": 8,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "{\n",
    "    // 在栈上创建一个长度为1000的数组\n",
    "    let arr = [0;1000];\n",
    "    // 将arr所有权转移arr1，由于 `arr` 分配在栈上，因此这里实际上是直接重新深拷贝了一份数据\n",
    "    let arr1 = arr;\n",
    "\n",
    "    // arr 和 arr1 都拥有各自的栈上数组，因此不会报错\n",
    "    println!(\"{:?}\", arr.len());\n",
    "    println!(\"{:?}\", arr1.len());\n",
    "\n",
    "    // 在堆上创建一个长度为1000的数组，然后使用一个智能指针指向它\n",
    "    let arr = Box::new([0;1000]);\n",
    "    // 将堆上数组的所有权转移给 arr1，由于数据在堆上，因此仅仅拷贝了智能指针的结构体，底层数据并没有被拷贝\n",
    "    // 所有权顺利转移给 arr1，arr 不再拥有所有权\n",
    "    let arr1 = arr;\n",
    "    println!(\"{:?}\", arr1.len());\n",
    "    // 由于 arr 不再拥有底层数组的所有权，因此下面代码将报错\n",
    "    // println!(\"{:?}\", arr.len());\n",
    "}"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "> Rust 语言规范里没有逐条写明“这个变量一定放在栈上”，但在实践中，只要局部变量的大小在编译期可知且不超过栈空间，编译器就会把它放到当前栈帧里"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "#### 将动态大小类型变为 Sized 固定大小类型\n",
    "\n",
    "Rust 需要在编译时知道类型占用多少空间，如果一种类型在编译时无法知道具体的大小，那么被称为动态大小类型 DST。\n",
    "\n",
    "其中一种无法在编译时知道大小的类型是**递归类型**：在类型定义中又使用到了自身，或者说该类型的值的一部分可以是相同类型的其它值，这种值的嵌套理论上可以无限进行下去，所以 Rust 不知道递归类型需要多少空间："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "metadata": {},
   "outputs": [
    {
     "ename": "Error",
     "evalue": "recursive type `List` has infinite size",
     "output_type": "error",
     "traceback": [
      "\u001b[31m[E0072] Error:\u001b[0m recursive type `List` has infinite size",
      "   \u001b[38;5;246m╭\u001b[0m\u001b[38;5;246m─\u001b[0m\u001b[38;5;246m[\u001b[0m command_9:1:1 \u001b[38;5;246m]\u001b[0m",
      "   \u001b[38;5;246m│\u001b[0m",
      " \u001b[38;5;246m1 │\u001b[0m \u001b[38;5;100me\u001b[0m\u001b[38;5;100mn\u001b[0m\u001b[38;5;100mu\u001b[0m\u001b[38;5;100mm\u001b[0m\u001b[38;5;100m \u001b[0m\u001b[38;5;100mL\u001b[0m\u001b[38;5;100mi\u001b[0m\u001b[38;5;100ms\u001b[0m\u001b[38;5;100mt\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249m{\u001b[0m",
      " \u001b[38;5;240m  │\u001b[0m \u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m┬\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m  ",
      " \u001b[38;5;240m  │\u001b[0m     \u001b[38;5;100m╰\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m error: recursive type `List` has infinite size",
      " \u001b[38;5;246m2 │\u001b[0m \u001b[38;5;249m \u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249mC\u001b[0m\u001b[38;5;249mo\u001b[0m\u001b[38;5;249mn\u001b[0m\u001b[38;5;249ms\u001b[0m\u001b[38;5;249m(\u001b[0m\u001b[38;5;249mi\u001b[0m\u001b[38;5;249m3\u001b[0m\u001b[38;5;249m2\u001b[0m\u001b[38;5;249m,\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;54mL\u001b[0m\u001b[38;5;54mi\u001b[0m\u001b[38;5;54ms\u001b[0m\u001b[38;5;54mt\u001b[0m\u001b[38;5;249m)\u001b[0m\u001b[38;5;249m,\u001b[0m",
      " \u001b[38;5;240m  │\u001b[0m               \u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m┬\u001b[0m\u001b[38;5;54m─\u001b[0m  ",
      " \u001b[38;5;240m  │\u001b[0m                 \u001b[38;5;54m╰\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m recursive without indirection",
      "\u001b[38;5;246m───╯\u001b[0m"
     ]
    }
   ],
   "source": [
    "enum List {\n",
    "    Cons(i32, List),\n",
    "    Nil,\n",
    "}"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "以上就是函数式语言中常见的 `Cons List`，它的每个节点包含一个 `i32` 值，还包含了一个新的 `List`，因此这种嵌套可以无限进行下去，Rust 认为该类型是一个 DST 类型，并给予报错："
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "此时若想解决这个问题，就可以使用我们的 `Box<T>`："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "enum List {\n",
    "    Cons(i32, Box<List>),\n",
    "    Nil,\n",
    "}"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "只需要将 `List` 存储到堆上，然后使用一个智能指针指向它，即可完成从 DST 到 Sized 类型(固定大小类型)的华丽转变。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "#### 特征对象\n",
    "\n",
    "在 Rust 中，想实现不同类型组成的数组只有两个办法：枚举和特征对象，前者限制较多，因此后者往往是最常用的解决办法。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "trait Draw {\n",
    "    fn draw(&self);\n",
    "}\n",
    "\n",
    "struct Button {\n",
    "    id: u32,\n",
    "}\n",
    "impl Draw for Button {\n",
    "    fn draw(&self) {\n",
    "        println!(\"这是屏幕上第{}号按钮\", self.id)\n",
    "    }\n",
    "}\n",
    "\n",
    "struct Select {\n",
    "    id: u32,\n",
    "}\n",
    "\n",
    "impl Draw for Select {\n",
    "    fn draw(&self) {\n",
    "        println!(\"这个选择框贼难用{}\", self.id)\n",
    "    }\n",
    "}\n",
    "\n",
    "{\n",
    "    let elems: Vec<Box<dyn Draw>> = vec![Box::new(Button { id: 1 }), Box::new(Select { id: 2 })];\n",
    "\n",
    "    for e in elems {\n",
    "        e.draw()\n",
    "    }\n",
    "}"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "以上代码将不同类型的 `Button` 和 `Select` 包装成 `Draw` 特征的特征对象，放入一个数组中，`Box<dyn Draw>` 就是特征对象。\n",
    "\n",
    "其实，特征也是 DST 类型，而特征对象在做的就是将 DST 类型转换为固定大小类型。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Box 内存布局\n",
    "\n",
    "先来看看 `Vec<i32>` 的内存布局："
   ]
  },
  {
   "cell_type": "raw",
   "metadata": {
    "vscode": {
     "languageId": "raw"
    }
   },
   "source": [
    "(stack)    (heap)\n",
    "┌──────┐   ┌───┐\n",
    "│ vec1 │──→│ 1 │\n",
    "└──────┘   ├───┤\n",
    "           │ 2 │\n",
    "           ├───┤\n",
    "           │ 3 │\n",
    "           ├───┤\n",
    "           │ 4 │\n",
    "           └───┘\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "之前提到过 `Vec` 和 `String` 都是智能指针，从上图可以看出，该智能指针存储在栈中，然后指向堆上的数组数据。\n",
    "\n",
    "那如果数组中每个元素都是一个 `Box` 对象呢？来看看 `Vec<Box<i32>>` 的内存布局："
   ]
  },
  {
   "cell_type": "raw",
   "metadata": {
    "vscode": {
     "languageId": "raw"
    }
   },
   "source": [
    "                    (heap)\n",
    "(stack)    (heap)   ┌───┐\n",
    "┌──────┐   ┌───┐ ┌─→│ 1 │\n",
    "│ vec2 │──→│B1 │─┘  └───┘\n",
    "└──────┘   ├───┤    ┌───┐\n",
    "           │B2 │───→│ 2 │\n",
    "           ├───┤    └───┘\n",
    "           │B3 │─┐  ┌───┐\n",
    "           ├───┤ └─→│ 3 │\n",
    "           │B4 │─┐  └───┘\n",
    "           └───┘ │  ┌───┐\n",
    "                 └─→│ 4 │\n",
    "                    └───┘"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "上面的 `B1` 代表被 `Box` 分配到堆上的值 `1`。\n",
    "\n",
    "可以看出智能指针 `vec2` 依然是存储在栈上，然后指针指向一个堆上的数组，该数组中每个元素都是一个 `Box` 智能指针，最终 `Box` 智能指针又指向了存储在堆上的实际值。\n",
    "\n",
    "因此当我们从数组中取出某个元素时，取到的是对应的智能指针 `Box`，需要对该智能指针进行解引用，才能取出最终的值："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "()"
      ]
     },
     "execution_count": 10,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "{\n",
    "    let arr = vec![Box::new(1), Box::new(2)];\n",
    "    let (first, second) = (&arr[0], &arr[1]);\n",
    "    let sum = **first + **second;\n",
    "}"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "以上代码有几个值得注意的点：\n",
    "\n",
    "- 使用 `&` 借用数组中的元素，否则会报所有权错误\n",
    "- 表达式不能隐式的解引用，因此必须使用 `**` 做两次解引用，第一次将 `&Box<i32>` 类型转成 `Box<i32>`，第二次将 `Box<i32>` 转成 `i32`"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Box::leak\n",
    "\n",
    "- `Box::leak` 消费一个 `Box<T>`，留下对内部值的可变或不可变引用，并让该值永远不被释放。\n",
    "- 常用于把运行期构造的值“提升”为 `'static` 引用，比如把 `String` 变成 `'static str`。\n",
    "- 适合需要全局、长生命周期数据的场景（配置、缓存等），且由你保证不会造成内存泄漏或重复释放。\n",
    "- 相比 `Rc/Arc` 等共享指针，`Box::leak` 无引用计数开销，但代价是该内存再也不会自动回收。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "hello, world\n"
     ]
    }
   ],
   "source": [
    "{\n",
    "   let s = gen_static_str();\n",
    "   println!(\"{}\", s);\n",
    "}\n",
    "\n",
    "fn gen_static_str() -> &'static str{\n",
    "    let mut s = String::new();\n",
    "    s.push_str(\"hello, world\");\n",
    "\n",
    "    Box::leak(s.into_boxed_str()) // 把一个 String 类型，变成一个 'static 生命周期的 &str 类型\n",
    "}"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 总结\n",
    "\n",
    "`Box` 背后是调用 `jemalloc` 来做内存管理，所以堆上的空间无需我们的手动管理。与此类似，带 GC 的语言中的对象也是借助于 `Box` 概念来实现的，**一切皆对象 = 一切皆 Box**， 只不过我们无需自己去 `Box` 罢了。\n",
    "\n",
    "其实很多时候，编译器的鞭笞可以助我们更快的成长，例如所有权规则里的借用、move、生命周期就是编译器在教我们做人，哦不是，是教我们深刻理解堆栈、内存布局、作用域等等你在其它 GC 语言无需去关注的东西。刚开始是很痛苦，但是一旦熟悉了这套规则，写代码的效率和代码本身的质量将飞速上升，直到你可以用 Java 开发的效率写出 Java 代码不可企及的性能和安全性，最终 Rust 语言所谓的开发效率低、心智负担高，对你来说终究不是个事。\n",
    "\n",
    "因此，不要怪 Rust，**它只是在帮我们成为那个更好的程序员，而这些苦难终究成为我们走向优秀的垫脚石**。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Deref 解引用\n",
    "\n",
    "- https://course.rs/advance/smart-pointer/deref.html\n",
    "\n",
    "TL;DR \n",
    "- `Deref` 让自定义智能指针像引用一样使用 `*`、方法调用、函数传参等场景无需手动解包。\n",
    "- `*ptr` 实际执行 `*(ptr.deref())`：先转换成常规引用，再解引用，避免所有权被夺走。\n",
    "- 隐式 `Deref` 转换仅发生在引用类型参数/接收者上，可连续链式展开（如 `Box<String>` → `String` → `&str`），零运行期开销。\n",
    "- `DerefMut` 扩展到可变引用，支持 `&mut T` → `&mut U`，同时允许 `&mut T` → `&U`（反向不允许）。\n",
    "- 编译器对多重引用与智能指针做“引用归一化”，自动降维成所需的 `&T`。\n",
    "- 实际开发中通常只给“智能指针”实现 `Deref`/`DerefMut`，避免滥用导致代码可读性下降。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "#[derive(Debug)]\n",
    "struct Person {\n",
    "    name: String,\n",
    "    age: u8\n",
    "}\n",
    "\n",
    "impl Person {\n",
    "    fn new(name: String, age: u8) -> Self {\n",
    "        Person { name, age}\n",
    "    }\n",
    "\n",
    "    fn display(self: &mut Person, age: u8) {\n",
    "        let Person{name, age} = &self;\n",
    "    }\n",
    "}"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "以上代码有一个很奇怪的地方：在 `display` 方法中，`self` 是 `&mut Person` 的类型，接着我们对其取了一次引用 `&self`，此时 `&self` 的类型是 `&&mut Person`，然后我们又将其和 `Person` 类型进行匹配，取出其中的值。\n",
    "\n",
    "那么问题来了，Rust 不是号称安全的语言吗？为何允许将 `&&mut Person` 跟 `Person` 进行匹配呢？"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "智能指针的名称来源，主要就在于它实现了 `Deref` 和 `Drop` 特征，这两个特征可以智能地帮助我们节省使用上的负担：\n",
    "\n",
    "- `Deref` 可以让智能指针像引用那样工作，这样你就可以写出同时支持智能指针和引用的代码，例如 `*T`\n",
    "- `Drop` 允许你指定智能指针超出作用域后自动执行的代码，例如做一些数据清除等收尾工作"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 通过 `*` 获取引用背后的值"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "()"
      ]
     },
     "execution_count": 3,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "{\n",
    "    let x = 5;\n",
    "    let y = &x;\n",
    "\n",
    "    assert_eq!(5, x);\n",
    "    assert_eq!(5, *y); // 常规引用是一个指针类型，包含了目标数据存储的内存地址。对常规引用使用 * 操作符，就可以通过解引用的方式获取到内存地址对应的数据值：\n",
    "}"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 智能指针解引用"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "()"
      ]
     },
     "execution_count": 4,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "{\n",
    "    let x = Box::new(1);\n",
    "    let sum = *x + 1; // 实现 Deref 后的智能指针结构体，就可以像普通引用一样，通过 * 进行解引用\n",
    "}"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 定义自己的智能指针"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {},
   "outputs": [],
   "source": [
    "struct MyBox<T>(T);\n",
    "\n",
    "impl<T> MyBox<T> {\n",
    "    fn new(x: T) -> MyBox<T> {\n",
    "        MyBox(x)\n",
    "    }\n",
    "}"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "metadata": {},
   "outputs": [
    {
     "ename": "Error",
     "evalue": "type `MyBox<{integer}>` cannot be dereferenced",
     "output_type": "error",
     "traceback": [
      "\u001b[31m[E0614] Error:\u001b[0m type `MyBox<{integer}>` cannot be dereferenced",
      "   \u001b[38;5;246m╭\u001b[0m\u001b[38;5;246m─\u001b[0m\u001b[38;5;246m[\u001b[0m command_6:1:1 \u001b[38;5;246m]\u001b[0m",
      "   \u001b[38;5;246m│\u001b[0m",
      " \u001b[38;5;246m4 │\u001b[0m \u001b[38;5;249m \u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249ma\u001b[0m\u001b[38;5;249ms\u001b[0m\u001b[38;5;249ms\u001b[0m\u001b[38;5;249me\u001b[0m\u001b[38;5;249mr\u001b[0m\u001b[38;5;249mt\u001b[0m\u001b[38;5;249m_\u001b[0m\u001b[38;5;249me\u001b[0m\u001b[38;5;249mq\u001b[0m\u001b[38;5;249m!\u001b[0m\u001b[38;5;249m(\u001b[0m\u001b[38;5;249m5\u001b[0m\u001b[38;5;249m,\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;54m*\u001b[0m\u001b[38;5;54my\u001b[0m\u001b[38;5;249m)\u001b[0m\u001b[38;5;249m;\u001b[0m",
      " \u001b[38;5;240m  │\u001b[0m                   \u001b[38;5;54m─\u001b[0m\u001b[38;5;54m┬\u001b[0m  ",
      " \u001b[38;5;240m  │\u001b[0m                    \u001b[38;5;54m╰\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m can't be dereferenced",
      "\u001b[38;5;246m───╯\u001b[0m"
     ]
    }
   ],
   "source": [
    "{\n",
    "    let y = MyBox::new(5);\n",
    "\n",
    "    assert_eq!(5, *y);\n",
    "}"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "**为智能指针实现 Deref 特征**"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "metadata": {},
   "outputs": [],
   "source": [
    "use std::ops::Deref;\n",
    "\n",
    "impl<T> Deref for MyBox<T> {\n",
    "    type Target = T;\n",
    "\n",
    "    fn deref(&self) -> &Self::Target {\n",
    "        &self.0\n",
    "    }\n",
    "}"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "()"
      ]
     },
     "execution_count": 8,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "{\n",
    "    let y = MyBox::new(5);\n",
    "\n",
    "    assert_eq!(5, *y);\n",
    "}"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## `*` 背后的原理"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "// 当我们对智能指针 Box 进行解引用时，实际上 Rust 为我们调用了以下方法：\n",
    "\n",
    "*(y.deref())"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "首先调用 `deref` 方法返回值的常规引用，然后通过 `*` 对常规引用进行解引用，最终获取到目标值。\n",
    "\n",
    "至于 Rust 为何要使用这个有点啰嗦的方式实现，原因在于所有权系统的存在。如果 `deref` 方法直接返回一个值，而不是引用，那么该值的所有权将被转移给调用者，而我们不希望调用者仅仅只是 `*T` 一下，就拿走了智能指针中包含的值。\n",
    "\n",
    "需要注意的是，`*` 不会无限递归替换，从 `*y` 到 `*(y.deref())` 只会发生一次，而不会继续进行替换然后产生形如 `*((y.deref()).deref())` 的怪物。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 函数和方法中的隐式 `Deref` 转换\n",
    "\n",
    "- 只要类型实现 `Deref`，它的引用在函数/方法调用时会按需求自动连环解引用，直到匹配参数的引用类型。\n",
    "- 触发条件：传入的是引用（如 `&String`），然后编译器尝试 `&String → &str → …`，完全在编译期完成，零运行期开销。\n",
    "- 普通函数、方法调用、字段访问、赋值等位置都会自动应用：`MyBox<String>` 也能直接传给需要 `&str` 的函数或调用 `to_string()`.\n",
    "- 便利代价是隐藏的类型转换会降低可读性；阅读代码时需留意背后是否发生了 `Deref` 链条。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "对于函数和方法的传参，Rust 提供了一个极其有用的隐式转换：`Deref `转换。若一个类型实现了 `Deref` 特征，那它的引用在传给函数或方法时，会根据参数签名来决定是否进行隐式的 `Deref` 转换，例如："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "{\n",
    "    let s = String::from(\"hello world\");\n",
    "    display(&s)\n",
    "}\n",
    "\n",
    "fn display(s: &str) {\n",
    "    println!(\"{}\",s);\n",
    "}"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "- `String` 实现了 `Deref` 特征，可以在需要时自动被转换为 `&str` 类型\n",
    "- `&s` 是一个 `&String` 类型，当它被传给 `display` 函数时，自动通过 `Deref` 转换成了 `&str`\n",
    "- 必须使用 `&s` 的方式来触发 `Deref`(仅引用类型的实参才会触发自动解引用)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "> AI:\n",
    "\n",
    "**`String` 与 `&str` 的关系**\n",
    "\n",
    "- `String` 是一个拥有者类型，里面有一块堆内存存放真正的字符串内容。\n",
    "- `&str` 是这块字符串内容的 **借用（引用）**，并不拥有数据。\n",
    "\n",
    "Rust 的标准库为 `String` 实现了 `Deref<Target = str>`。这意味着：\n",
    "\n",
    "> 当你拿到一个 `String` 的引用 `&String` 时，编译器可以“把它当成” `&str` 来用。\n",
    "\n",
    "这就是所谓的 `Deref` 转换或 `deref` 强制。\n",
    "\n",
    "**`&s` 是 `&String`，为何能传给 `display`**\n",
    "\n",
    "`&s` 的实际类型是 `&String`。\n",
    "\n",
    "当 Rust 看到你把 `&String` 传给需要 `&str` 的函数时，会这样做：\n",
    "\n",
    "1. 发现实参是 `&String`，而 `display` 要求 `&str`。\n",
    "2. 检查 `String` 有没有实现 `Deref`，发现实现了 `Deref<Target = str>`。\n",
    "3. 编译器自动把 `&String` 转换成 `&str`。\n",
    "\n",
    "这个转换过程叫做 **隐式 Deref 转换**（有时也叫“deref 强制”）。\n",
    "\n",
    "**为什么“必须使用 `&s` 才触发”**\n",
    "\n",
    "因为只有“引用”才能触发这个自动过程。\n",
    "\n",
    "- 写 `display(&s)` → 传入 `&String`，编译器自动转换成 `&str`。\n",
    "- 如果写 `display(s)` → 试图传 `String`，类型根本不匹配，连 `Deref` 都派不上用场。\n",
    "\n",
    "同理，`display(*s)` 也不行，因为 `*s` 用在 `String` 上会报错（你无法直接解引用一个 `String` 数据，它不是指针）。\n",
    "\n",
    "**你没感受到转换，是因为这是编译期发生的**\n",
    "\n",
    "```rust\n",
    "display(&s);\n",
    "```\n",
    "\n",
    "虽然你写的是 `&s`，但 Rust 编译器 **在编译阶段** 就帮你把它转换成了 `&str`，运行时没有任何额外开销。\n",
    "\n",
    "如果你手动写出这个转换，会是这样的：\n",
    "\n",
    "```rust\n",
    "display(&*s);       // deref 一次：&String -> &str\n",
    "display(&s[..]);    // 用切片方式拿到 &str\n",
    "display(s.as_str()); // 调用 as_str() 拿到 &str\n",
    "```"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "#### * 连续的隐式 Deref 转换\n",
    "\n",
    "`Deref` 可以支持连续的隐式转换，直到找到适合的形式为止："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "hello world\n"
     ]
    }
   ],
   "source": [
    "{\n",
    "    let s = MyBox::new(String::from(\"hello world\")); // 首先 `MyBox` 被 `Deref` 成 `String` 类型，结果并不能满足 `display` 函数参数的要求，编译器发现 `String` 还可以继续 `Deref` 成 `&str`，最终成功的匹配了函数参数。\n",
    "    display(&s)\n",
    "}\n",
    "\n",
    "fn display(s: &str) {\n",
    "    println!(\"{}\",s);\n",
    "}"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Rust\n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "()"
      ]
     },
     "execution_count": 10,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "{\n",
    "    let m = MyBox::new(String::from(\"Rust\"));\n",
    "    display(&(*m)[..]); // 没有提供这种隐式转换的调用\n",
    "}"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 11,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "()"
      ]
     },
     "execution_count": 11,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "{\n",
    "    let s = MyBox::new(String::from(\"hello, world\"));\n",
    "    let s1: &str = &s;\n",
    "    let s2: String = s.to_string();\n",
    "}"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "对于 `s1`，我们通过两次 `Deref` 将 `&str` 类型的值赋给了它（**赋值操作需要手动解引用**）；而对于 `s2`，我们在其上直接调用方法 `to_string`，实际上 `MyBox` 根本没有没有实现该方法，能调用 `to_string`，完全是因为编译器对 `MyBox` 应用了 `Deref` 的结果（**方法调用会自动解引用**）。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## `Deref` 规则总结\n",
    "\n",
    "一个类型为 `T` 的对象 `foo`，如果 `T: Deref<Target=U>`，那么，相关 `foo` 的引用 `&foo` 在应用的时候会自动转换为 `&U`。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### [引用归一化](https://course.rs/advance/smart-pointer/deref.html#引用归一化)\n",
    "\n",
    "Rust 编译器实际上只能对 `&v` 形式的引用进行解引用操作，那么问题来了，如果是一个智能指针或者 `&&&&v` 类型的呢？ 该如何对这两个进行解引用？\n",
    "\n",
    "答案是：Rust 会在解引用时自动把智能指针和 `&&&&v` 做引用归一化操作，转换成 `&v` 形式，最终再对 `&v` 进行解引用：\n",
    "\n",
    "- 把智能指针（比如在库中定义的，Box、Rc、Arc、Cow 等）从结构体脱壳为内部的引用类型，也就是转成结构体内部的 `&v`\n",
    "- 把多重`&`，例如 `&&&&&&&v`，归一成 `&v`"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "// 标准库源码\n",
    "\n",
    "impl<T: ?Sized> Deref for &T {\n",
    "    type Target = T;\n",
    "\n",
    "    fn deref(&self) -> &T {\n",
    "        *self\n",
    "    }\n",
    "}"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "在这段源码中，`&T` 被自动解引用为 `T`，也就是 `&T: Deref<Target=T>` 。 按照这个代码，`&&&&T` 会被自动解引用为 `&&&T`，然后再自动解引用为 `&&T`，以此类推， 直到最终变成 `&T`。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "> AI:\n",
    "\n",
    "- `&T` 也实现了 `Deref`，目标类型还是 `T`。\n",
    "- 每次 `.deref()` 都会把外层 `&` 去掉一层。\n",
    "\n",
    "所以如果你有 `&&&&T`，编译器会这样处理：\n",
    "```shell\n",
    "&&&&T\n",
    "   ↓ 1 次 Deref\n",
    "&&&T\n",
    "   ↓ 1 次 Deref\n",
    "&&T\n",
    "   ↓ 1 次 Deref\n",
    "&T\n",
    "```\n",
    "最后得到单层 `&T`，再进入最终的解引用。\n",
    "\n",
    "> 当你写 `*something`，无论 `something `是 `&T`、`&&T` 还是 `Box<T>`，编译器都会自动帮你把它转换到 `&T` 的形式，再进行一次真正的解引用。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "//  LLVM 编译后的部分中间层代码\n",
    "\n",
    "// Rust 代码\n",
    "let mut _2: &i32;\n",
    "let _3: &&&&i32; \n",
    "\n",
    "bb0: {\n",
    "    _2 = (*(*(*_3))) // 这里 _3 是 &&&&i32，MIR 用三次 * 把它归一化为单层 &i32，赋值给 _2，观察的是编译器内部的处理过程。\n",
    "}"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "**几个例子**"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 14,
   "metadata": {},
   "outputs": [],
   "source": [
    "fn foo(s: &str) {}\n",
    "\n",
    "// 由于 String 实现了 Deref<Target=str>\n",
    "let owned = \"Hello\".to_string();\n",
    "\n",
    "// 因此下面的函数可以正常运行：\n",
    "foo(&owned);\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 15,
   "metadata": {},
   "outputs": [],
   "source": [
    "use std::rc::Rc;\n",
    "\n",
    "fn foo(s: &str) {}\n",
    "\n",
    "// String 实现了 Deref<Target=str>\n",
    "let owned = \"Hello\".to_string();\n",
    "// 且 Rc 智能指针可以被自动脱壳为内部的 `owned` 引用： &String ，然后 &String 再自动解引用为 &str\n",
    "let counted = Rc::new(owned);\n",
    "\n",
    "// 因此下面的函数可以正常运行:\n",
    "foo(&counted);\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 16,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Foo\n",
      "Foo\n",
      "Foo\n",
      "Foo\n"
     ]
    }
   ],
   "source": [
    "struct Foo;\n",
    "\n",
    "impl Foo {\n",
    "    fn foo(&self) { println!(\"Foo\"); }\n",
    "}\n",
    "\n",
    "let f = &&Foo;\n",
    "\n",
    "f.foo();\n",
    "(&f).foo();\n",
    "(&&f).foo();\n",
    "(&&&&&&&&f).foo();"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## * 三种 `Deref` 转换\n",
    "\n",
    "在之前，我们讲的都是不可变的 `Deref` 转换，实际上 Rust 还支持将一个可变的引用转换成另一个可变的引用以及将一个可变引用转换成不可变的引用，规则如下：\n",
    "\n",
    "1. `T: Deref<Target = U>` ⇒ `&T` 自动变成 `&U`\n",
    "2. `T: DerefMut<Target = U>` ⇒ `&mut T` 自动变成 `&mut U`\n",
    "3. `T: Deref<Target = U>` ⇒ `&mut T` 也能自动变成 `&U`（可变引用降级为不可变引用）"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "hello, world\n"
     ]
    }
   ],
   "source": [
    "struct MyBox<T> {\n",
    "    v: T,\n",
    "}\n",
    "\n",
    "impl<T> MyBox<T> {\n",
    "    fn new(x: T) -> MyBox<T> {\n",
    "        MyBox { v: x }\n",
    "    }\n",
    "}\n",
    "\n",
    "use std::ops::Deref;\n",
    "\n",
    "impl<T> Deref for MyBox<T> {\n",
    "    type Target = T;\n",
    "\n",
    "    fn deref(&self) -> &Self::Target {\n",
    "        &self.v\n",
    "    }\n",
    "}\n",
    "\n",
    "use std::ops::DerefMut;\n",
    "\n",
    "impl<T> DerefMut for MyBox<T> {\n",
    "    fn deref_mut(&mut self) -> &mut Self::Target {\n",
    "        &mut self.v\n",
    "    }\n",
    "}\n",
    "\n",
    "{\n",
    "    let mut s = MyBox::new(String::from(\"hello, \"));\n",
    "    display(&mut s)\n",
    "}\n",
    "\n",
    "fn display(s: &mut String) {\n",
    "    s.push_str(\"world\");\n",
    "    println!(\"{}\", s);\n",
    "}"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "- `MyBox` 先实现 `Deref` 再实现 `DerefMut`（因为 `DerefMut`：`pub trait DerefMut: Deref { ... }`）。\n",
    "- `display` 接受 `&mut String`，而调用时传入 `&mut MyBox<String>`，编译器据规则 2 自动转换。\n",
    "- 若在别处只需不可变引用，依然可以把 `&mut MyBox<T>` 自动降级成 `&U`（规则 3）。\n",
    "\n",
    "记住：Rust 允许“更强”借用自动变成“更弱”借用，但绝不允许反之。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 总结\n",
    "\n",
    "`Deref` 可以说是 Rust 中最常见的隐式类型转换，而且它可以连续的实现如 `Box<String> -> String -> &str` 的隐式转换，只要链条上的类型实现了 `Deref` 特征。\n",
    "\n",
    "我们也可以为自己的类型实现 `Deref` 特征，但是原则上来说，只应该为自定义的智能指针实现 `Deref`。例如，虽然你可以为自己的自定义数组类型实现 `Deref` 以避免 `myArr.0[0]` 的使用形式，但是 Rust 官方并不推荐这么做，特别是在你开发三方库时。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Drop 释放资源\n",
    "\n",
    "- https://course.rs/advance/smart-pointer/drop.html"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Rust 中的资源回收\n",
    "\n",
    "在一些无 GC 语言中，程序员在一个变量无需再被使用时，需要手动释放它占用的内存资源，如果忘记了，那么就会发生内存泄漏，最终臭名昭著的 `OOM` 问题可能就会发生。\n",
    "\n",
    "而在 Rust 中，你可以指定在一个变量超出作用域时，执行一段特定的代码，最终编译器将帮你自动插入这段收尾代码。这样，就无需在每一个使用该变量的地方，都写一段代码来进行收尾工作和资源释放。不禁让人感叹，Rust 的大腿真粗，香！\n",
    "\n",
    "没错，指定这样一段收尾工作靠的就是咱这章的主角 - `Drop` 特征。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 一个不那么简单的 Drop 例子"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Running!\n",
      "Dropping Foo!\n",
      "Dropping HasTwoDrops!\n",
      "Dropping HasDrop1!\n",
      "Dropping HasDrop2!\n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "()"
      ]
     },
     "execution_count": 4,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "struct HasDrop1;\n",
    "\n",
    "impl Drop for HasDrop1 {\n",
    "    fn drop(&mut self) {\n",
    "        println!(\"Dropping HasDrop1!\");\n",
    "    }\n",
    "}\n",
    "\n",
    "struct HasDrop2;\n",
    "impl Drop for HasDrop2 {\n",
    "    fn drop(&mut self) {\n",
    "        println!(\"Dropping HasDrop2!\");\n",
    "    }\n",
    "}\n",
    "\n",
    "struct HasTwoDrops {\n",
    "    one: HasDrop1,\n",
    "    two: HasDrop2,\n",
    "}\n",
    "impl Drop for HasTwoDrops {\n",
    "    fn drop(&mut self) {\n",
    "        println!(\"Dropping HasTwoDrops!\");\n",
    "    }\n",
    "}\n",
    "\n",
    "struct Foo;\n",
    "impl Drop for Foo {\n",
    "    fn drop(&mut self) {\n",
    "        println!(\"Dropping Foo!\")\n",
    "    }\n",
    "}\n",
    "\n",
    "{\n",
    "    let _x = HasTwoDrops {\n",
    "        two: HasDrop2,\n",
    "        one: HasDrop1,\n",
    "    };\n",
    "    let _foo = Foo;\n",
    "    println!(\"Running!\");\n",
    "}"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "结构体中每个字段都有自己的 `Drop`"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### [Drop 的顺序](https://course.rs/advance/smart-pointer/drop.html#drop-的顺序)\n",
    "\n",
    "观察以上输出，我们可以得出以下关于 `Drop` 顺序的结论\n",
    "\n",
    "- **变量级别，按照逆序的方式**，`_x` 在 `_foo` 之前创建，因此 `_x` 在 `_foo` 之后被 `drop`\n",
    "- **结构体内部，按照顺序的方式**，结构体 `_x` 中的字段按照定义中的顺序依次 `drop`"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### [没有实现 Drop 的结构体](https://course.rs/advance/smart-pointer/drop.html#没有实现-drop-的结构体)\n",
    "\n",
    "实际上，就算你不为 `_x` 结构体实现 `Drop` 特征，它内部的两个字段依然会调用 `drop`，移除以下代码，并观察输出："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Running!\n",
      "Dropping Foo!\n",
      "Dropping HasDrop1!\n",
      "Dropping HasDrop2!\n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "()"
      ]
     },
     "execution_count": 5,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "struct HasDrop1;\n",
    "\n",
    "impl Drop for HasDrop1 {\n",
    "    fn drop(&mut self) {\n",
    "        println!(\"Dropping HasDrop1!\");\n",
    "    }\n",
    "}\n",
    "\n",
    "struct HasDrop2;\n",
    "impl Drop for HasDrop2 {\n",
    "    fn drop(&mut self) {\n",
    "        println!(\"Dropping HasDrop2!\");\n",
    "    }\n",
    "}\n",
    "\n",
    "struct HasTwoDrops {\n",
    "    one: HasDrop1,\n",
    "    two: HasDrop2,\n",
    "}\n",
    "\n",
    "struct Foo;\n",
    "impl Drop for Foo {\n",
    "    fn drop(&mut self) {\n",
    "        println!(\"Dropping Foo!\")\n",
    "    }\n",
    "}\n",
    "\n",
    "{\n",
    "    let _x = HasTwoDrops {\n",
    "        two: HasDrop2,\n",
    "        one: HasDrop1,\n",
    "    };\n",
    "    let _foo = Foo;\n",
    "    println!(\"Running!\");\n",
    "}"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "原因在于，Rust 自动为几乎所有类型都实现了 `Drop` 特征，因此就算你不手动为结构体实现 `Drop`，它依然会调用默认实现的 `drop` 函数，同时再调用每个字段的 `drop` 方法，最终打印出："
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 手动回收"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [
    {
     "ename": "Error",
     "evalue": "explicit use of destructor method",
     "output_type": "error",
     "traceback": [
      "\u001b[31m[E0040] Error:\u001b[0m explicit use of destructor method",
      "    \u001b[38;5;246m╭\u001b[0m\u001b[38;5;246m─\u001b[0m\u001b[38;5;246m[\u001b[0m command_7:1:1 \u001b[38;5;246m]\u001b[0m",
      "    \u001b[38;5;246m│\u001b[0m",
      " \u001b[38;5;246m12 │\u001b[0m \u001b[38;5;249m \u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249mf\u001b[0m\u001b[38;5;249mo\u001b[0m\u001b[38;5;249mo\u001b[0m\u001b[38;5;249m.\u001b[0m\u001b[38;5;54md\u001b[0m\u001b[38;5;54mr\u001b[0m\u001b[38;5;54mo\u001b[0m\u001b[38;5;54mp\u001b[0m\u001b[38;5;249m(\u001b[0m\u001b[38;5;249m)\u001b[0m\u001b[38;5;249m;\u001b[0m",
      " \u001b[38;5;240m   │\u001b[0m         \u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m┬\u001b[0m\u001b[38;5;54m─\u001b[0m  ",
      " \u001b[38;5;240m   │\u001b[0m           \u001b[38;5;54m╰\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m explicit destructor calls not allowed",
      "\u001b[38;5;246m────╯\u001b[0m"
     ]
    }
   ],
   "source": [
    "#[derive(Debug)]\n",
    "struct Foo;\n",
    "\n",
    "impl Drop for Foo {\n",
    "    fn drop(&mut self) {\n",
    "        println!(\"Dropping Foo!\")\n",
    "    }\n",
    "}\n",
    "\n",
    "{\n",
    "    let foo = Foo;\n",
    "    foo.drop(); // \n",
    "    println!(\"Running!:{:?}\", foo); // `Drop::drop` 只是借用了目标值的可变引用，所以，就算你提前调用了 `drop`，后面的代码依然可以使用目标值，但是这就会访问一个并不存在的值，非常不安全\n",
    "}                                   // 对于 Rust 而言，不允许显式地调用析构函数（这是一个用来清理实例的通用编程概念）"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Dropping Foo!\n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "()"
      ]
     },
     "execution_count": 8,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "{\n",
    "    let foo = Foo;\n",
    "    drop(foo);\n",
    "    // 以下代码会报错：借用了所有权被转移的值\n",
    "    // println!(\"Running!:{:?}\", foo);\n",
    "}"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "metadata": {},
   "outputs": [
    {
     "ename": "Error",
     "evalue": "borrow of moved value: `foo`",
     "output_type": "error",
     "traceback": [
      "\u001b[31m[E0382] Error:\u001b[0m borrow of moved value: `foo`",
      "   \u001b[38;5;246m╭\u001b[0m\u001b[38;5;246m─\u001b[0m\u001b[38;5;246m[\u001b[0m command_10:1:1 \u001b[38;5;246m]\u001b[0m",
      "   \u001b[38;5;246m│\u001b[0m",
      " \u001b[38;5;246m5 │\u001b[0m \u001b[38;5;249m \u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249ml\u001b[0m\u001b[38;5;249me\u001b[0m\u001b[38;5;249mt\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;68mf\u001b[0m\u001b[38;5;68mo\u001b[0m\u001b[38;5;68mo\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249m=\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249mF\u001b[0m\u001b[38;5;249mo\u001b[0m\u001b[38;5;249mo\u001b[0m\u001b[38;5;249m;\u001b[0m",
      " \u001b[38;5;240m  │\u001b[0m         \u001b[38;5;68m─\u001b[0m\u001b[38;5;68m┬\u001b[0m\u001b[38;5;68m─\u001b[0m  ",
      " \u001b[38;5;240m  │\u001b[0m          \u001b[38;5;68m╰\u001b[0m\u001b[38;5;68m─\u001b[0m\u001b[38;5;68m─\u001b[0m\u001b[38;5;68m─\u001b[0m move occurs because `foo` has type `Foo`, which does not implement the `Copy` trait",
      " \u001b[38;5;246m6 │\u001b[0m \u001b[38;5;249m \u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249md\u001b[0m\u001b[38;5;249mr\u001b[0m\u001b[38;5;249mo\u001b[0m\u001b[38;5;249mp\u001b[0m\u001b[38;5;249m(\u001b[0m\u001b[38;5;54mf\u001b[0m\u001b[38;5;54mo\u001b[0m\u001b[38;5;54mo\u001b[0m\u001b[38;5;249m)\u001b[0m\u001b[38;5;249m;\u001b[0m",
      " \u001b[38;5;240m  │\u001b[0m          \u001b[38;5;54m─\u001b[0m\u001b[38;5;54m┬\u001b[0m\u001b[38;5;54m─\u001b[0m  ",
      " \u001b[38;5;240m  │\u001b[0m           \u001b[38;5;54m╰\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m value moved here",
      " \u001b[38;5;246m7 │\u001b[0m \u001b[38;5;249m \u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249mp\u001b[0m\u001b[38;5;249mr\u001b[0m\u001b[38;5;249mi\u001b[0m\u001b[38;5;249mn\u001b[0m\u001b[38;5;249mt\u001b[0m\u001b[38;5;249ml\u001b[0m\u001b[38;5;249mn\u001b[0m\u001b[38;5;249m!\u001b[0m\u001b[38;5;249m(\u001b[0m\u001b[38;5;249m\"\u001b[0m\u001b[38;5;249mR\u001b[0m\u001b[38;5;249mu\u001b[0m\u001b[38;5;249mn\u001b[0m\u001b[38;5;249mn\u001b[0m\u001b[38;5;249mi\u001b[0m\u001b[38;5;249mn\u001b[0m\u001b[38;5;249mg\u001b[0m\u001b[38;5;249m!\u001b[0m\u001b[38;5;249m:\u001b[0m\u001b[38;5;249m{\u001b[0m\u001b[38;5;249m:\u001b[0m\u001b[38;5;249m?\u001b[0m\u001b[38;5;249m}\u001b[0m\u001b[38;5;249m\"\u001b[0m\u001b[38;5;249m,\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;100mf\u001b[0m\u001b[38;5;100mo\u001b[0m\u001b[38;5;100mo\u001b[0m\u001b[38;5;249m)\u001b[0m\u001b[38;5;249m;\u001b[0m",
      " \u001b[38;5;240m  │\u001b[0m                               \u001b[38;5;100m─\u001b[0m\u001b[38;5;100m┬\u001b[0m\u001b[38;5;100m─\u001b[0m  ",
      " \u001b[38;5;240m  │\u001b[0m                                \u001b[38;5;100m╰\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m value borrowed here after move",
      "\u001b[38;5;246m───╯\u001b[0m"
     ]
    }
   ],
   "source": [
    "#[derive(Debug)]\n",
    "struct Foo;\n",
    "\n",
    "{\n",
    "    let foo = Foo;\n",
    "    drop(foo);\n",
    "    println!(\"Running!:{:?}\", foo);\n",
    "}"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Drop 使用场景\n",
    "\n",
    "对于 Drop 而言，主要有两个功能：\n",
    "\n",
    "- 回收内存资源\n",
    "- 执行一些收尾工作\n",
    "\n",
    "对于第二点，在之前我们已经详细介绍过，因此这里主要对第一点进行下简单说明。\n",
    "\n",
    "在绝大多数情况下，我们都无需手动去 `drop` 以回收内存资源，因为 Rust 会自动帮我们完成这些工作，它甚至会对复杂类型的每个字段都单独的调用 `drop` 进行回收！但是确实有极少数情况，需要你自己来回收资源的，例如文件描述符、网络 socket 等，当这些值超出作用域不再使用时，就需要进行关闭以释放相关的资源，在这些情况下，就需要使用者自己来解决 `Drop` 的问题。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 互斥的 Copy 和 Drop\n",
    "\n",
    "我们无法为一个类型同时实现 `Copy` 和 `Drop` 特征。因为实现了 `Copy` 特征的类型会被编译器隐式的复制，因此非常难以预测析构函数执行的时间和频率。因此这些实现了 `Copy` 的类型无法拥有析构函数。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 11,
   "metadata": {},
   "outputs": [
    {
     "ename": "Error",
     "evalue": "the trait `Copy` cannot be implemented for this type; the type has a destructor",
     "output_type": "error",
     "traceback": [
      "\u001b[31m[E0184] Error:\u001b[0m the trait `Copy` cannot be implemented for this type; the type has a destructor",
      "   \u001b[38;5;246m╭\u001b[0m\u001b[38;5;246m─\u001b[0m\u001b[38;5;246m[\u001b[0m command_11:1:1 \u001b[38;5;246m]\u001b[0m",
      "   \u001b[38;5;246m│\u001b[0m",
      " \u001b[38;5;246m1 │\u001b[0m \u001b[38;5;249m#\u001b[0m\u001b[38;5;249m[\u001b[0m\u001b[38;5;249md\u001b[0m\u001b[38;5;249me\u001b[0m\u001b[38;5;249mr\u001b[0m\u001b[38;5;249mi\u001b[0m\u001b[38;5;249mv\u001b[0m\u001b[38;5;249me\u001b[0m\u001b[38;5;249m(\u001b[0m\u001b[38;5;54mC\u001b[0m\u001b[38;5;54mo\u001b[0m\u001b[38;5;54mp\u001b[0m\u001b[38;5;54my\u001b[0m\u001b[38;5;249m)\u001b[0m\u001b[38;5;249m]\u001b[0m",
      " \u001b[38;5;240m  │\u001b[0m          \u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m┬\u001b[0m\u001b[38;5;54m─\u001b[0m  ",
      " \u001b[38;5;240m  │\u001b[0m            \u001b[38;5;54m╰\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m `Copy` not allowed on types with destructors",
      "\u001b[38;5;246m───╯\u001b[0m"
     ]
    }
   ],
   "source": [
    "#[derive(Copy)]\n",
    "struct Foo;\n",
    "\n",
    "impl Drop for Foo {\n",
    "    fn drop(&mut self) {\n",
    "        println!(\"Dropping Foo!\")\n",
    "    }\n",
    "}"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 总结\n",
    "\n",
    "`Drop` 可以用于许多方面，来使得资源清理及收尾工作变得方便和安全，甚至可以用其创建我们自己的内存分配器！通过 `Drop` 特征和 Rust 所有权系统，你无需担心之后的代码清理，Rust 会自动考虑这些问题。\n",
    "\n",
    "我们也无需担心意外的清理掉仍在使用的值，这会造成编译器错误：所有权系统确保引用总是有效的，也会确保 `drop` 只会在值不再被使用时被调用一次。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# * Rc 与 Arc 实现 1vN 所有权机制\n",
    "\n",
    "- https://course.rs/advance/smart-pointer/rc-arc.html\n",
    "\n",
    "- **共同点**\n",
    "  - 都是智能指针，基于引用计数管理堆上数据的共享所有权。\n",
    "  - 提供不可变共享访问：多个所有者只能读，不能直接改。\n",
    "  - 引用计数归零时，底层数据自动释放。\n",
    "  - 想要“读写共享”，需搭配内部可变性（`RefCell<T>`）或同步原语（`Mutex<T>` 等）。\n",
    "- **`Rc<T>`（Reference Counted）**\n",
    "  - 单线程使用，`std::rc::Rc`。\n",
    "  - 引用计数非原子，速度快但线程不安全。\n",
    "  - 常用场景：图结构、树状数据在同一线程内共享节点。\n",
    "- **`Arc<T>`（Atomic Reference Counted）**\n",
    "  - 多线程使用，`std::sync::Arc`。\n",
    "  - 引用计数使用原子操作，线程安全但略慢。\n",
    "  - 常与 `Mutex<T>` / `RwLock<T>` 组合在多线程中共享可变数据。\n",
    "- **使用要点**\n",
    "  - 克隆智能指针请用 `Rc::clone` / `Arc::clone`，仅增引用计数，不复制底层数据。\n",
    "  - 不要混用 `Rc` 与 `Arc`；按线程需求选一个。\n",
    "  - 析构通过 `Drop` 自动完成，手动 `drop` 只会减少计数，并不会立刻毁掉底层数据（除非计数归零）"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Rust 所有权机制要求一个值只能有一个所有者，在大多数情况下，都没有问题，但是考虑以下情况：\n",
    "\n",
    "- 在图数据结构中，多个边可能会拥有同一个节点，该节点直到没有边指向它时，才应该被释放清理\n",
    "- 在多线程中，多个线程可能会持有同一个数据，但是你受限于 Rust 的安全机制，无法同时获取该数据的可变引用\n",
    "\n",
    "以上场景不是很常见，但是一旦遇到，就非常棘手，为了解决此类问题，Rust 在所有权机制之外又引入了额外的措施来简化相应的实现：通过引用计数的方式，允许一个数据资源在同一时刻拥有多个所有者。\n",
    "\n",
    "这种实现机制就是 `Rc` 和 `Arc`，前者适用于单线程，后者适用于多线程。由于二者大部分情况下都相同，因此本章将以 `Rc` 作为讲解主体，对于 `Arc` 的不同之处，另外进行单独讲解。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## [`Rc`](https://course.rs/advance/smart-pointer/rc-arc.html#rct)\n",
    "\n",
    "引用计数(reference counting)，顾名思义，通过记录一个数据被引用的次数来确定该数据是否正在被使用。当引用次数归零时，就代表该数据不再被使用，因此可以被清理释放。\n",
    "\n",
    "而 `Rc` 正是引用计数的英文缩写。当我们**希望在堆上分配一个对象供程序的多个部分使用且无法确定哪个部分最后一个结束时，就可以使用 `Rc` 成为数据值的所有者**，例如之前提到的多线程场景就非常适合。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "()"
      ]
     },
     "execution_count": 12,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "// 经典的所有权被转移导致报错的例子\n",
    "{\n",
    "    let s = String::from(\"hello, world\");\n",
    "    // s在这里被转移给a\n",
    "    let a = Box::new(s);\n",
    "    // 报错！此处继续尝试将 s 转移给 b\n",
    "    // let b = Box::new(s);\n",
    "}"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 13,
   "metadata": {},
   "outputs": [
    {
     "ename": "Error",
     "evalue": "unused variable: `a`",
     "output_type": "error",
     "traceback": [
      "\u001b[31m[unused_variables] Error:\u001b[0m unused variable: `a`",
      "   \u001b[38;5;246m╭\u001b[0m\u001b[38;5;246m─\u001b[0m\u001b[38;5;246m[\u001b[0m command_13:1:1 \u001b[38;5;246m]\u001b[0m",
      "   \u001b[38;5;246m│\u001b[0m",
      " \u001b[38;5;246m3 │\u001b[0m \u001b[38;5;249m \u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249ml\u001b[0m\u001b[38;5;249me\u001b[0m\u001b[38;5;249mt\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;54ma\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249m=\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249mB\u001b[0m\u001b[38;5;249mo\u001b[0m\u001b[38;5;249mx\u001b[0m\u001b[38;5;249m:\u001b[0m\u001b[38;5;249m:\u001b[0m\u001b[38;5;249mn\u001b[0m\u001b[38;5;249me\u001b[0m\u001b[38;5;249mw\u001b[0m\u001b[38;5;249m(\u001b[0m\u001b[38;5;249ms\u001b[0m\u001b[38;5;249m)\u001b[0m\u001b[38;5;249m;\u001b[0m",
      " \u001b[38;5;240m  │\u001b[0m         \u001b[38;5;54m┬\u001b[0m  ",
      " \u001b[38;5;240m  │\u001b[0m         \u001b[38;5;54m╰\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m warning: unused variable: `a`",
      " \u001b[38;5;240m  │\u001b[0m         \u001b[38;5;100m│\u001b[0m  ",
      " \u001b[38;5;240m  │\u001b[0m         \u001b[38;5;100m╰\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m help: if this is intentional, prefix it with an underscore: `_a`",
      "\u001b[38;5;246m───╯\u001b[0m"
     ]
    },
    {
     "ename": "Error",
     "evalue": "unused variable: `b`",
     "output_type": "error",
     "traceback": [
      "\u001b[31m[unused_variables] Error:\u001b[0m unused variable: `b`",
      "   \u001b[38;5;246m╭\u001b[0m\u001b[38;5;246m─\u001b[0m\u001b[38;5;246m[\u001b[0m command_13:1:1 \u001b[38;5;246m]\u001b[0m",
      "   \u001b[38;5;246m│\u001b[0m",
      " \u001b[38;5;246m4 │\u001b[0m \u001b[38;5;249m \u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249ml\u001b[0m\u001b[38;5;249me\u001b[0m\u001b[38;5;249mt\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;54mb\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249m=\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249mB\u001b[0m\u001b[38;5;249mo\u001b[0m\u001b[38;5;249mx\u001b[0m\u001b[38;5;249m:\u001b[0m\u001b[38;5;249m:\u001b[0m\u001b[38;5;249mn\u001b[0m\u001b[38;5;249me\u001b[0m\u001b[38;5;249mw\u001b[0m\u001b[38;5;249m(\u001b[0m\u001b[38;5;249ms\u001b[0m\u001b[38;5;249m)\u001b[0m\u001b[38;5;249m;\u001b[0m",
      " \u001b[38;5;240m  │\u001b[0m         \u001b[38;5;54m┬\u001b[0m  ",
      " \u001b[38;5;240m  │\u001b[0m         \u001b[38;5;54m╰\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m warning: unused variable: `b`",
      " \u001b[38;5;240m  │\u001b[0m         \u001b[38;5;100m│\u001b[0m  ",
      " \u001b[38;5;240m  │\u001b[0m         \u001b[38;5;100m╰\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m help: if this is intentional, prefix it with an underscore: `_b`",
      "\u001b[38;5;246m───╯\u001b[0m"
     ]
    },
    {
     "ename": "Error",
     "evalue": "use of moved value: `s`",
     "output_type": "error",
     "traceback": [
      "\u001b[31m[E0382] Error:\u001b[0m use of moved value: `s`",
      "   \u001b[38;5;246m╭\u001b[0m\u001b[38;5;246m─\u001b[0m\u001b[38;5;246m[\u001b[0m command_13:1:1 \u001b[38;5;246m]\u001b[0m",
      "   \u001b[38;5;246m│\u001b[0m",
      " \u001b[38;5;246m2 │\u001b[0m \u001b[38;5;249m \u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249ml\u001b[0m\u001b[38;5;249me\u001b[0m\u001b[38;5;249mt\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;68ms\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249m=\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249mS\u001b[0m\u001b[38;5;249mt\u001b[0m\u001b[38;5;249mr\u001b[0m\u001b[38;5;249mi\u001b[0m\u001b[38;5;249mn\u001b[0m\u001b[38;5;249mg\u001b[0m\u001b[38;5;249m:\u001b[0m\u001b[38;5;249m:\u001b[0m\u001b[38;5;249mf\u001b[0m\u001b[38;5;249mr\u001b[0m\u001b[38;5;249mo\u001b[0m\u001b[38;5;249mm\u001b[0m\u001b[38;5;249m(\u001b[0m\u001b[38;5;249m\"\u001b[0m\u001b[38;5;249mh\u001b[0m\u001b[38;5;249me\u001b[0m\u001b[38;5;249ml\u001b[0m\u001b[38;5;249ml\u001b[0m\u001b[38;5;249mo\u001b[0m\u001b[38;5;249m,\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249mw\u001b[0m\u001b[38;5;249mo\u001b[0m\u001b[38;5;249mr\u001b[0m\u001b[38;5;249ml\u001b[0m\u001b[38;5;249md\u001b[0m\u001b[38;5;249m\"\u001b[0m\u001b[38;5;249m)\u001b[0m\u001b[38;5;249m;\u001b[0m",
      " \u001b[38;5;240m  │\u001b[0m         \u001b[38;5;68m┬\u001b[0m  ",
      " \u001b[38;5;240m  │\u001b[0m         \u001b[38;5;68m╰\u001b[0m\u001b[38;5;68m─\u001b[0m\u001b[38;5;68m─\u001b[0m move occurs because `s` has type `String`, which does not implement the `Copy` trait",
      " \u001b[38;5;246m3 │\u001b[0m \u001b[38;5;249m \u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249ml\u001b[0m\u001b[38;5;249me\u001b[0m\u001b[38;5;249mt\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249ma\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249m=\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249mB\u001b[0m\u001b[38;5;249mo\u001b[0m\u001b[38;5;249mx\u001b[0m\u001b[38;5;249m:\u001b[0m\u001b[38;5;249m:\u001b[0m\u001b[38;5;249mn\u001b[0m\u001b[38;5;249me\u001b[0m\u001b[38;5;249mw\u001b[0m\u001b[38;5;249m(\u001b[0m\u001b[38;5;54ms\u001b[0m\u001b[38;5;249m)\u001b[0m\u001b[38;5;249m;\u001b[0m",
      " \u001b[38;5;240m  │\u001b[0m                      \u001b[38;5;54m┬\u001b[0m\u001b[38;5;37m│\u001b[0m ",
      " \u001b[38;5;240m  │\u001b[0m                      \u001b[38;5;54m╰\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m value moved here",
      " \u001b[38;5;240m  │\u001b[0m                       \u001b[38;5;37m│\u001b[0m ",
      " \u001b[38;5;240m  │\u001b[0m                       \u001b[38;5;37m╰\u001b[0m\u001b[38;5;37m─\u001b[0m help: consider cloning the value if the performance cost is acceptable: `.clone()`",
      " \u001b[38;5;246m4 │\u001b[0m \u001b[38;5;249m \u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249ml\u001b[0m\u001b[38;5;249me\u001b[0m\u001b[38;5;249mt\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249mb\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249m=\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249mB\u001b[0m\u001b[38;5;249mo\u001b[0m\u001b[38;5;249mx\u001b[0m\u001b[38;5;249m:\u001b[0m\u001b[38;5;249m:\u001b[0m\u001b[38;5;249mn\u001b[0m\u001b[38;5;249me\u001b[0m\u001b[38;5;249mw\u001b[0m\u001b[38;5;249m(\u001b[0m\u001b[38;5;100ms\u001b[0m\u001b[38;5;249m)\u001b[0m\u001b[38;5;249m;\u001b[0m",
      " \u001b[38;5;240m  │\u001b[0m                      \u001b[38;5;100m┬\u001b[0m  ",
      " \u001b[38;5;240m  │\u001b[0m                      \u001b[38;5;100m╰\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m value used here after move",
      "\u001b[38;5;246m───╯\u001b[0m"
     ]
    }
   ],
   "source": [
    "{\n",
    "    let s = String::from(\"hello, world\");\n",
    "    let a = Box::new(s);\n",
    "    let b = Box::new(s);\n",
    "}"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "- 使用 `Rc` 就可以轻易解决："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 14,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "()"
      ]
     },
     "execution_count": 14,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "use std::rc::Rc;\n",
    "\n",
    "{\n",
    "    let a = Rc::new(String::from(\"hello, world\"));\n",
    "    let b = Rc::clone(&a);\n",
    "\n",
    "    assert_eq!(2, Rc::strong_count(&a));\n",
    "    assert_eq!(Rc::strong_count(&a), Rc::strong_count(&b))\n",
    "}"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "以上代码我们使用 `Rc::new` 创建了一个新的 `Rc<String>` 智能指针并赋给变量 `a`，该指针指向底层的字符串数据。\n",
    "\n",
    "智能指针 `Rc<T>` 在创建时，还会将引用计数加 1，此时获取引用计数的关联函数 `Rc::strong_count` 返回的值将是 `1`。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### [Rc::clone](https://course.rs/advance/smart-pointer/rc-arc.html#rcclone)\n",
    "\n",
    "接着，我们又使用 `Rc::clone` 克隆了一份智能指针 `Rc<String>`，并将该智能指针的引用计数增加到 `2`。\n",
    "\n",
    "由于 `a` 和 `b` 是同一个智能指针的两个副本，因此通过它们两个获取引用计数的结果都是 `2`。\n",
    "\n",
    "不要被 `clone` 字样所迷惑，以为所有的 `clone` 都是深拷贝。这里的 `clone` **仅仅复制了智能指针并增加了引用计数，并没有克隆底层数据**，因此 `a` 和 `b` 是共享了底层的字符串 `s`，这种**复制效率是非常高**的。当然你也可以使用 `a.clone()` 的方式来克隆，但是从可读性角度，我们更加推荐 `Rc::clone` 的方式。\n",
    "\n",
    "实际上在 Rust 中，还有不少 `clone` 都是浅拷贝，例如[迭代器的克隆](https://course.rs/compiler/pitfalls/iterator-everywhere.html)。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### [观察引用计数的变化](https://course.rs/advance/smart-pointer/rc-arc.html#观察引用计数的变化)\n",
    "\n",
    "使用关联函数 `Rc::strong_count` 可以获取当前引用计数的值，我们来观察下引用计数如何随着变量声明、释放而变化："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 15,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "count after creating a = 1\n",
      "count after creating b = 2\n",
      "count after creating c = 3\n",
      "count after c goes out of scope = 2\n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "()"
      ]
     },
     "execution_count": 15,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "use std::rc::Rc;\n",
    "\n",
    "{\n",
    "    let a = Rc::new(String::from(\"test ref counting\"));\n",
    "    println!(\"count after creating a = {}\", Rc::strong_count(&a));\n",
    "    let b =  Rc::clone(&a);\n",
    "    println!(\"count after creating b = {}\", Rc::strong_count(&a));\n",
    "    {\n",
    "        let c =  Rc::clone(&a);\n",
    "        println!(\"count after creating c = {}\", Rc::strong_count(&c));\n",
    "    }\n",
    "    println!(\"count after c goes out of scope = {}\", Rc::strong_count(&a));\n",
    "}"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "有几点值得注意：\n",
    "\n",
    "- 由于变量 `c` 在语句块内部声明，当离开语句块时它会因为超出作用域而被释放，所以引用计数会减少 1，事实上这个得益于 `Rc<T>` 实现了 `Drop` 特征\n",
    "- `a`、`b`、`c` 三个智能指针引用计数都是同样的，并且共享底层的数据，因此打印计数时用哪个都行\n",
    "- 无法看到的是：当 `a`、`b` 超出作用域后，引用计数会变成 0，最终智能指针和它指向的底层字符串都会被清理释放"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### [不可变引用](https://course.rs/advance/smart-pointer/rc-arc.html#不可变引用)\n",
    "\n",
    "事实上，`Rc<T>` 是指向底层数据的不可变的引用，因此你无法通过它来修改数据，这也符合 Rust 的借用规则：要么存在多个不可变借用，要么只能存在一个可变借用。\n",
    "\n",
    "但是实际开发中我们往往需要对数据进行修改，这时单独使用 `Rc<T>` 无法满足我们的需求，需要配合其它数据类型来一起使用，例如内部可变性的 `RefCell<T>` 类型以及互斥锁 `Mutex<T>`。事实上，在多线程编程中，`Arc` 跟 `Mutex` 锁的组合使用非常常见，它们既可以让我们在不同的线程中共享数据，又允许在各个线程中对其进行修改。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### [一个综合例子](https://course.rs/advance/smart-pointer/rc-arc.html#一个综合例子)\n",
    "\n",
    "考虑一个场景，有很多小工具，每个工具都有自己的主人，但是存在多个工具属于同一个主人的情况，此时使用 `Rc<T>` 就非常适合："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 16,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Gadget 1 owned by Gadget Man\n",
      "Gadget 2 owned by Gadget Man\n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "()"
      ]
     },
     "execution_count": 16,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "use std::rc::Rc;\n",
    "\n",
    "struct Owner {\n",
    "    name: String,\n",
    "    // ...其它字段\n",
    "}\n",
    "\n",
    "struct Gadget {\n",
    "    id: i32,\n",
    "    owner: Rc<Owner>,\n",
    "    // ...其它字段\n",
    "}\n",
    "\n",
    "{\n",
    "    // 创建一个基于引用计数的 `Owner`.\n",
    "    let gadget_owner: Rc<Owner> = Rc::new(Owner {\n",
    "        name: \"Gadget Man\".to_string(),\n",
    "    });\n",
    "\n",
    "    // 创建两个不同的工具，它们属于同一个主人\n",
    "    let gadget1 = Gadget {\n",
    "        id: 1,\n",
    "        owner: Rc::clone(&gadget_owner),\n",
    "    };\n",
    "    let gadget2 = Gadget {\n",
    "        id: 2,\n",
    "        owner: Rc::clone(&gadget_owner),\n",
    "    };\n",
    "\n",
    "    // 释放掉第一个 `Rc<Owner>`\n",
    "    drop(gadget_owner);\n",
    "\n",
    "    // 尽管在上面我们释放了 gadget_owner，但是依然可以在这里使用 owner 的信息\n",
    "    // 原因是在 drop 之前，存在三个指向 Gadget Man 的智能指针引用，上面仅仅\n",
    "    // drop 掉其中一个智能指针引用，而不是 drop 掉 owner 数据，外面还有两个\n",
    "    // 引用指向底层的 owner 数据，引用计数尚未清零\n",
    "    // 因此 owner 数据依然可以被使用\n",
    "    println!(\"Gadget {} owned by {}\", gadget1.id, gadget1.owner.name);\n",
    "    println!(\"Gadget {} owned by {}\", gadget2.id, gadget2.owner.name);\n",
    "\n",
    "    // 在函数最后，`gadget1` 和 `gadget2` 也被释放，最终引用计数归零，随后底层\n",
    "    // 数据也被清理释放\n",
    "}"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "以上代码很好的展示了 `Rc<T>` 的用途，当然你也可以用借用的方式，但是实现起来就会复杂得多，而且随着 `Gadget` 在代码的各个地方使用，引用生命周期也将变得更加复杂，毕竟结构体中的引用类型，总是令人不那么愉快，对不？"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### [Rc 简单总结](https://course.rs/advance/smart-pointer/rc-arc.html#rc-简单总结)\n",
    "\n",
    "- `Rc/Arc` 是不可变引用，你无法修改它指向的值，只能进行读取，如果要修改，需要配合后面章节的内部可变性 `RefCell` 或互斥锁 `Mutex`\n",
    "- 一旦最后一个拥有者消失，则资源会自动被回收，这个生命周期是在编译期就确定下来的\n",
    "- `Rc` 只能用于同一线程内部，想要用于线程之间的对象共享，你需要使用 `Arc`\n",
    "- `Rc<T>` 是一个智能指针，实现了 `Deref` 特征，因此你无需先解开 `Rc` 指针，再使用里面的 `T`，而是可以直接使用 `T`，例如上例中的 `gadget1.owner.name`"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## [多线程无力的 `Rc`](https://course.rs/advance/smart-pointer/rc-arc.html#多线程无力的-rct)\n",
    "\n",
    "来看看在多线程场景使用 `Rc<T>` 会如何："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 18,
   "metadata": {},
   "outputs": [
    {
     "ename": "Error",
     "evalue": "`Rc<String>` cannot be sent between threads safely",
     "output_type": "error",
     "traceback": [
      "\u001b[31m[E0277] Error:\u001b[0m `Rc<String>` cannot be sent between threads safely",
      "    \u001b[38;5;246m╭\u001b[0m\u001b[38;5;246m─\u001b[0m\u001b[38;5;246m[\u001b[0m command_18:1:1 \u001b[38;5;246m]\u001b[0m",
      "    \u001b[38;5;246m│\u001b[0m",
      " \u001b[38;5;246m 8 │\u001b[0m \u001b[38;5;54m╭\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m▶\u001b[0m\u001b[38;5;54m \u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249ml\u001b[0m\u001b[38;5;249me\u001b[0m\u001b[38;5;249mt\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249mh\u001b[0m\u001b[38;5;249ma\u001b[0m\u001b[38;5;249mn\u001b[0m\u001b[38;5;249md\u001b[0m\u001b[38;5;249ml\u001b[0m\u001b[38;5;249me\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249m=\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;68mt\u001b[0m\u001b[38;5;68mh\u001b[0m\u001b[38;5;68mr\u001b[0m\u001b[38;5;68me\u001b[0m\u001b[38;5;68ma\u001b[0m\u001b[38;5;68md\u001b[0m\u001b[38;5;68m:\u001b[0m\u001b[38;5;68m:\u001b[0m\u001b[38;5;68ms\u001b[0m\u001b[38;5;68mp\u001b[0m\u001b[38;5;68ma\u001b[0m\u001b[38;5;68mw\u001b[0m\u001b[38;5;68mn\u001b[0m\u001b[38;5;249m(\u001b[0m\u001b[38;5;100mm\u001b[0m\u001b[38;5;100mo\u001b[0m\u001b[38;5;100mv\u001b[0m\u001b[38;5;100me\u001b[0m\u001b[38;5;100m \u001b[0m\u001b[38;5;100m|\u001b[0m\u001b[38;5;100m|\u001b[0m\u001b[38;5;54m \u001b[0m\u001b[38;5;54m{\u001b[0m",
      " \u001b[38;5;240m   │\u001b[0m \u001b[38;5;54m│\u001b[0m                        \u001b[38;5;68m─\u001b[0m\u001b[38;5;68m─\u001b[0m\u001b[38;5;68m─\u001b[0m\u001b[38;5;68m─\u001b[0m\u001b[38;5;68m─\u001b[0m\u001b[38;5;68m─\u001b[0m\u001b[38;5;68m┬\u001b[0m\u001b[38;5;68m─\u001b[0m\u001b[38;5;68m─\u001b[0m\u001b[38;5;68m─\u001b[0m\u001b[38;5;68m─\u001b[0m\u001b[38;5;68m─\u001b[0m\u001b[38;5;68m─\u001b[0m \u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m┬\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m  ",
      " \u001b[38;5;240m   │\u001b[0m \u001b[38;5;54m│\u001b[0m                              \u001b[38;5;68m╰\u001b[0m\u001b[38;5;68m─\u001b[0m\u001b[38;5;68m─\u001b[0m\u001b[38;5;68m─\u001b[0m\u001b[38;5;68m─\u001b[0m\u001b[38;5;68m─\u001b[0m\u001b[38;5;68m─\u001b[0m\u001b[38;5;68m─\u001b[0m\u001b[38;5;68m─\u001b[0m\u001b[38;5;68m─\u001b[0m\u001b[38;5;68m─\u001b[0m\u001b[38;5;68m─\u001b[0m\u001b[38;5;68m─\u001b[0m\u001b[38;5;68m─\u001b[0m\u001b[38;5;68m─\u001b[0m\u001b[38;5;68m─\u001b[0m\u001b[38;5;68m─\u001b[0m required by a bound introduced by this call",
      " \u001b[38;5;240m   │\u001b[0m \u001b[38;5;54m│\u001b[0m                                         \u001b[38;5;100m│\u001b[0m     ",
      " \u001b[38;5;240m   │\u001b[0m \u001b[38;5;54m│\u001b[0m                                         \u001b[38;5;100m╰\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m within this `{closure@src/lib.rs:194:36: 194:43}`",
      " \u001b[38;5;240m   │\u001b[0m \u001b[38;5;54m│\u001b[0m                                         \u001b[38;5;37m│\u001b[0m     ",
      " \u001b[38;5;240m   │\u001b[0m \u001b[38;5;54m│\u001b[0m                                         \u001b[38;5;37m╰\u001b[0m\u001b[38;5;37m─\u001b[0m\u001b[38;5;37m─\u001b[0m\u001b[38;5;37m─\u001b[0m\u001b[38;5;37m─\u001b[0m\u001b[38;5;37m─\u001b[0m note: required because it's used within this closure",
      " \u001b[38;5;240m   ┆\u001b[0m \u001b[38;5;54m┆\u001b[0m   ",
      " \u001b[38;5;246m10 │\u001b[0m \u001b[38;5;54m├\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m▶\u001b[0m\u001b[38;5;54m \u001b[0m\u001b[38;5;54m \u001b[0m\u001b[38;5;54m \u001b[0m\u001b[38;5;54m \u001b[0m\u001b[38;5;54m \u001b[0m\u001b[38;5;54m \u001b[0m\u001b[38;5;54m \u001b[0m\u001b[38;5;54m \u001b[0m\u001b[38;5;54m \u001b[0m\u001b[38;5;54m}\u001b[0m\u001b[38;5;249m)\u001b[0m\u001b[38;5;249m;\u001b[0m",
      " \u001b[38;5;240m   │\u001b[0m \u001b[38;5;54m│\u001b[0m                 ",
      " \u001b[38;5;240m   │\u001b[0m \u001b[38;5;54m╰\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m `Rc<String>` cannot be sent between threads safely",
      "\u001b[38;5;246m────╯\u001b[0m"
     ]
    }
   ],
   "source": [
    "use std::rc::Rc;\n",
    "use std::thread;\n",
    "\n",
    "{\n",
    "    let s = Rc::new(String::from(\"muti-thread walker\"));\n",
    "    for _ in 0..10 {\n",
    "        let s = Rc::clone(&s);\n",
    "        let handle = thread::spawn(move || {\n",
    "           println!(\"{}\", s)\n",
    "        });\n",
    "    }\n",
    "}"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "由于我们还没有学习多线程的章节，上面的例子就特地简化了相关的实现。首先通过 `thread::spawn` 创建一个线程，然后使用 `move` 关键字把克隆出的 `s` 的所有权转移到线程中。\n",
    "\n",
    "能够实现这一点，完全得益于 `Rc` 带来的多所有权机制，但是以上代码会报错：\n",
    "\n",
    "表面原因是 `Rc<T>` 不能在线程间安全的传递，实际上是因为它没有实现 `Send` 特征，而该特征是恰恰是多线程间传递数据的关键，我们会在多线程章节中进行讲解。\n",
    "\n",
    "当然，还有更深层的原因：由于 `Rc<T>` 需要管理引用计数，但是该计数器并没有使用任何并发原语，因此无法实现原子化的计数操作，最终会导致计数错误。\n",
    "\n",
    "好在天无绝人之路，一起来看看 Rust 为我们提供的功能类似但是多线程安全的 `Arc`。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## [Arc](https://course.rs/advance/smart-pointer/rc-arc.html#arc)\n",
    "\n",
    "`Arc` 是 `Atomic Rc` 的缩写，顾名思义：原子化的 `Rc<T>` 智能指针。原子化是一种并发原语，我们在后续章节会进行深入讲解，这里你只要知道它能保证我们的数据能够安全的在线程间共享即可。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## [Arc 的性能损耗](https://course.rs/advance/smart-pointer/rc-arc.html#arc-的性能损耗)\n",
    "\n",
    "你可能好奇，为何不直接使用 `Arc`，还要画蛇添足弄一个 `Rc`，还有 Rust 的基本数据类型、标准库数据类型为什么不自动实现原子化操作？这样就不存在线程不安全的问题了。\n",
    "\n",
    "原因在于原子化或者其它锁虽然可以带来的线程安全，但是都会伴随着性能损耗，而且这种性能损耗还不小。因此 Rust 把这种选择权交给你，毕竟需要线程安全的代码其实占比并不高，大部分时候我们开发的程序都在一个线程内。\n",
    "\n",
    "`Arc` 和 `Rc` 拥有完全一样的 API，修改起来很简单："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 19,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "muti-thread walker\n",
      "muti-thread walker\n",
      "muti-thread walker\n",
      "muti-thread walker\n",
      "muti-thread walker\n",
      "muti-thread walker\n",
      "muti-thread walker\n",
      "muti-thread walker\n",
      "muti-thread walker\n",
      "muti-thread walker\n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "()"
      ]
     },
     "execution_count": 19,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "use std::sync::Arc;\n",
    "use std::thread;\n",
    "\n",
    "{\n",
    "    let s = Arc::new(String::from(\"muti-thread walker\"));\n",
    "    for _ in 0..10 {\n",
    "        let s = Arc::clone(&s);\n",
    "        let handle = thread::spawn(move || {\n",
    "           println!(\"{}\", s)\n",
    "        });\n",
    "    }\n",
    "}"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "对了，两者还有一点区别：`Arc` 和 `Rc` 并没有定义在同一个模块，前者通过 `use std::sync::Arc` 来引入，后者通过 `use std::rc::Rc`。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## [总结](https://course.rs/advance/smart-pointer/rc-arc.html#总结)\n",
    "\n",
    "在 Rust 中，所有权机制保证了一个数据只会有一个所有者，但如果你想要在图数据结构、多线程等场景中共享数据，这种机制会成为极大的阻碍。好在 Rust 为我们提供了智能指针 `Rc` 和 `Arc`，使用它们就能实现多个所有者共享一个数据的功能。\n",
    "\n",
    "`Rc` 和 `Arc` 的区别在于，后者是原子化实现的引用计数，因此是线程安全的，可以用于多线程中共享数据。\n",
    "\n",
    "这两者都是只读的，如果想要实现内部数据可修改，必须配合内部可变性 `RefCell` 或者互斥锁 `Mutex` 来一起使用。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# * Cell 与 RefCell 内部可变性\n",
    "\n",
    "- https://course.rs/advance/smart-pointer/cell-refcell.html\n",
    "\n",
    "- **共同点**\n",
    "\n",
    "  - 都提供“内部可变性”：即使只有不可变引用，也能修改包裹的数据。\n",
    "  - 违反借用规则不会在编译期报错，而是推迟到运行期检查（`Cell` 不会 panic，`RefCell` 会）。\n",
    "\n",
    "- **`Cell<T>`**\n",
    "\n",
    "  - 适用于 **实现了 `Copy` 的值类型**。\n",
    "  - API 是按值读写：`get()` 返回拷贝，`set()` 写入新值。\n",
    "  - 编译时零开销，完全不会运行期 panic。\n",
    "  - 常见用途：简单标志位、数值、小型 Copy 数据需要内部可变性。\n",
    "\n",
    "- **`RefCell<T>`**\n",
    "\n",
    "  - 用于 **非 `Copy` 的数据或需要引用语义**。\n",
    "  - 通过 `borrow()` / `borrow_mut()` 动态检查借用规则，违规时 **运行期 panic**。\n",
    "  - 适合编译器无法证明合法、但逻辑上你确信安全的共享可变场景。\n",
    "  - 常与 `Rc<T>`／`Arc<T>` 搭配，解决“多所有者 + 可变访问”。\n",
    "\n",
    "- **选择指南**\n",
    "\n",
    "  | 需求                 | 选 `Cell`     | 选 `RefCell`               |\n",
    "  | -------------------- | ------------- | -------------------------- |\n",
    "  | 数据是否 `Copy`      | ✅             | ❌（可，但通常没必要）      |\n",
    "  | 需要返回引用         | ❌             | ✅                          |\n",
    "  | 是否容忍运行期 panic | ✅（无 panic） | ⚠️（违规会 panic）          |\n",
    "  | 性能敏感             | ✅ 零额外成本  | ✅ 但有少量借用状态检查开销 |\n",
    "\n",
    "- **组合技**\n",
    "\n",
    "  - `Rc<RefCell<T>>`：多所有者共享且可变（单线程）。\n",
    "  - `Arc<Mutex<T>>` 或 `Arc<RefCell<T>>`：多线程场景需换成同步原语。\n",
    "\n",
    "- **额外提示**\n",
    "\n",
    "  - `Cell::from_mut` / `Cell::as_slice_of_cells` 可把 `&mut [T]` 转为 `&[Cell<T>]`，借此解除迭代器 vs 可变借用冲突。\n",
    "  - 内部可变性是“必要时使用”的逃生门：确保逻辑正确性、必要时做运行期断言，并在热点路径跑基准测试。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Rust 的编译器之严格，可以说是举世无双。特别是在所有权方面，Rust 通过严格的规则来保证所有权和借用的正确性，最终为程序的安全保驾护航。\n",
    "\n",
    "但是严格是一把双刃剑，带来安全提升的同时，损失了灵活性，有时甚至会让用户痛苦不堪、怨声载道。因此 Rust 提供了 `Cell` 和 `RefCell` 用于内部可变性，简而言之，可以在拥有不可变引用的同时修改目标数据，对于正常的代码实现来说，这个是不可能做到的（要么一个可变借用，要么多个不可变借用）。\n",
    "\n",
    "> 内部可变性的实现是因为 Rust 使用了 `unsafe` 来做到这一点，但是对于使用者来说，这些都是透明的，因为这些不安全代码都被封装到了安全的 API 中"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## [Cell](https://course.rs/advance/smart-pointer/cell-refcell.html#cell)\n",
    "\n",
    "`Cell` 和 `RefCell` 在功能上没有区别，区别在于 `Cell<T>` 适用于 `T` 实现 `Copy` 的情况："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 20,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "asdf,qwer\n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "()"
      ]
     },
     "execution_count": 20,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "use std::cell::Cell;\n",
    "\n",
    "{\n",
    "  let c = Cell::new(\"asdf\");\n",
    "  let one = c.get();\n",
    "  c.set(\"qwer\");\n",
    "  let two = c.get();\n",
    "  println!(\"{},{}\", one, two);\n",
    "}"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "以上代码展示了 `Cell` 的基本用法，有几点值得注意：\n",
    "\n",
    "- `\"asdf\"` 是 `&str` 类型，它实现了 `Copy` 特征\n",
    "- `c.get` 用来取值，`c.set` 用来设置新值\n",
    "\n",
    "> `\"asdf\"` 是 `&str` 类型:\n",
    "> 在 Rust 中，字符串字面量（例如 `\"asdf\"`）的类型默认就是 `&'static str`。这是编译器在解析源代码时就确定下来的，因为：\n",
    "> 1. **字符串字面量存放在可执行文件的静态只读数据段里**，整个程序生命周期都存在，所以它的生命周期标记为 `'static`。\n",
    "> 2. **字面量本身是一个不可变的 UTF-8 字节序列的切片**，因此类型是对这段数据的引用，也就是 `&str`。结合生命周期，就得到 `&'static str`。\n",
    "\n",
    "取到值保存在 `one` 变量后，还能同时进行修改，这个违背了 Rust 的借用规则，但是由于 `Cell` 的存在，我们很优雅地做到了这一点，但是如果你尝试在 `Cell` 中存放`String`："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 23,
   "metadata": {},
   "outputs": [
    {
     "ename": "Error",
     "evalue": "the method `get` exists for struct `Cell<String>`, but its trait bounds were not satisfied",
     "output_type": "error",
     "traceback": [
      "\u001b[31m[E0599] Error:\u001b[0m the method `get` exists for struct `Cell<String>`, but its trait bounds were not satisfied",
      "   \u001b[38;5;246m╭\u001b[0m\u001b[38;5;246m─\u001b[0m\u001b[38;5;246m[\u001b[0m command_23:1:1 \u001b[38;5;246m]\u001b[0m",
      "   \u001b[38;5;246m│\u001b[0m",
      " \u001b[38;5;246m5 │\u001b[0m \u001b[38;5;249m \u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249ml\u001b[0m\u001b[38;5;249me\u001b[0m\u001b[38;5;249mt\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249ms\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249m=\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249mc\u001b[0m\u001b[38;5;249m.\u001b[0m\u001b[38;5;54mg\u001b[0m\u001b[38;5;54me\u001b[0m\u001b[38;5;54mt\u001b[0m\u001b[38;5;249m(\u001b[0m\u001b[38;5;249m)\u001b[0m\u001b[38;5;249m;\u001b[0m",
      " \u001b[38;5;240m  │\u001b[0m               \u001b[38;5;54m─\u001b[0m\u001b[38;5;54m┬\u001b[0m\u001b[38;5;54m─\u001b[0m  ",
      " \u001b[38;5;240m  │\u001b[0m                \u001b[38;5;54m╰\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m error: the method `get` exists for struct `Cell<String>`, but its trait bounds were not satisfied",
      "\u001b[38;5;246m───╯\u001b[0m"
     ]
    }
   ],
   "source": [
    "use std::cell::Cell;\n",
    "\n",
    "{\n",
    "    let c = Cell::new(String::from(\"asdf\"));\n",
    "    let s = c.get(); \n",
    "}"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## [RefCell](https://course.rs/advance/smart-pointer/cell-refcell.html#refcell)\n",
    "\n",
    "由于 `Cell` 类型针对的是实现了 `Copy` 特征的值类型，因此在实际开发中，`Cell` 使用的并不多，因为我们要解决的往往是可变、不可变引用共存导致的问题，此时就需要借助于 `RefCell` 来达成目的。\n",
    "\n",
    "我们可以将所有权、借用规则与这些智能指针做一个对比：\n",
    "\n",
    "| Rust 规则                            | 智能指针带来的额外规则                  |\n",
    "| ------------------------------------ | --------------------------------------- |\n",
    "| 一个数据只有一个所有者               | `Rc/Arc`让一个数据可以拥有多个所有者    |\n",
    "| 要么多个不可变借用，要么一个可变借用 | `RefCell`实现编译期可变、不可变引用共存 |\n",
    "| 违背规则导致**编译错误**             | 违背规则导致**运行时`panic`**           |\n",
    "\n",
    "可以看出，`Rc/Arc` 和 `RefCell` 合在一起，解决了 Rust 中严苛的所有权和借用规则带来的某些场景下难使用的问题。但是它们并不是银弹，例如 `RefCell` 实际上并没有解决可变引用和引用可以共存的问题，只是将报错从编译期推迟到运行时，从编译器错误变成了 `panic` 异常："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 24,
   "metadata": {},
   "outputs": [
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "\n",
      "thread '<unnamed>' panicked at src/lib.rs:189:16:\n",
      "RefCell already borrowed\n",
      "stack backtrace:\n",
      "   0: __rustc::rust_begin_unwind\n",
      "             at /rustc/1159e78c4747b02ef996e55082b704c09b970588/library/std/src/panicking.rs:697:5\n",
      "   1: core::panicking::panic_fmt\n",
      "             at /rustc/1159e78c4747b02ef996e55082b704c09b970588/library/core/src/panicking.rs:75:14\n",
      "   2: core::cell::panic_already_borrowed::do_panic::runtime\n",
      "             at /rustc/1159e78c4747b02ef996e55082b704c09b970588/library/core/src/panic.rs:218:21\n",
      "   3: core::cell::panic_already_borrowed::do_panic\n",
      "             at /rustc/1159e78c4747b02ef996e55082b704c09b970588/library/core/src/intrinsics/mod.rs:2367:9\n",
      "   4: core::cell::panic_already_borrowed\n",
      "             at /rustc/1159e78c4747b02ef996e55082b704c09b970588/library/core/src/panic.rs:223:9\n",
      "   5: ctx::run_user_code_14::{{closure}}\n",
      "   6: __rust_try.llvm.13968780337059443206\n",
      "   7: std::panic::catch_unwind\n",
      "   8: run_user_code_14\n",
      "   9: evcxr::runtime::Runtime::run_loop\n",
      "  10: evcxr::runtime::runtime_hook\n",
      "  11: evcxr_jupyter::main\n",
      "note: Some details are omitted, run with `RUST_BACKTRACE=full` for a verbose backtrace.\n"
     ]
    }
   ],
   "source": [
    "use std::cell::RefCell;\n",
    "\n",
    "{\n",
    "    let s = RefCell::new(String::from(\"hello, world\"));\n",
    "    let s1 = s.borrow();\n",
    "    let s2 = s.borrow_mut();\n",
    "\n",
    "    println!(\"{},{}\", s1, s2);\n",
    "}"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "依然会因为违背了借用规则导致了运行期 `panic`，这非常像中国的天网，它也许会被罪犯蒙蔽一时，但是并不会被蒙蔽一世，任何导致安全风险的存在都将不能被容忍，法网恢恢，疏而不漏。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### [RefCell 为何存在](https://course.rs/advance/smart-pointer/cell-refcell.html#refcell-为何存在)\n",
    "\n",
    "Rust 编译器在借用检查上奉行“宁可错杀，不容误放”，有时会对逻辑上安全但结构复杂的代码发出“误报”。\n",
    "\n",
    "`RefCell<T>` 通过运行时借用检查，让我们在不可变引用的外壳内，对内部数据进行可变访问，从而绕过编译器保守的静态限制。\n",
    "\n",
    "它特别适合：\n",
    "\n",
    "- 你确信操作安全、但编译器无法证明的场景；\n",
    "- 大型代码中广泛共享、跨模块更新的状态（例如 Rust 编译器的上下文结构）。\n",
    "\n",
    "如果借用被错误地使用，`RefCell` 会在运行时 panic，直接指出冲突位置，便于调试。\n",
    "\n",
    "因此，`RefCell` 是在“灵活性”与“编译器严格保证”之间的折中手段，用运行时检查换取更易组织的代码结构。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### [RefCell 简单总结](https://course.rs/advance/smart-pointer/cell-refcell.html#refcell-简单总结)\n",
    "\n",
    "- 与 `Cell` 用于可 `Copy` 的值不同，`RefCell` 用于引用\n",
    "- `RefCell` 只是将借用规则从编译期推迟到程序运行期，并不能帮你绕过这个规则\n",
    "- `RefCell` 适用于编译期误报或者一个引用被在多处代码使用、修改以至于难于管理借用关系时\n",
    "- 使用 `RefCell` 时，违背借用规则会导致运行期的 `panic`"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## [选择 `Cell` 还是 `RefCell`](https://course.rs/advance/smart-pointer/cell-refcell.html#选择-cell-还是-refcell)\n",
    "\n",
    "根据本文的内容，我们可以大概总结下两者的区别：\n",
    "\n",
    "- `Cell` 只适用于 `Copy` 类型，用于提供值，而 `RefCell` 用于提供引用\n",
    "- `Cell` 不会 `panic`，而 `RefCell` 会"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### [性能比较](https://course.rs/advance/smart-pointer/cell-refcell.html#性能比较)\n",
    "\n",
    "`Cell` 没有额外的性能损耗，例如以下两段代码的性能其实是一致的："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "4\n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "()"
      ]
     },
     "execution_count": 27,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "// code snipet 1\n",
    "{\n",
    "  let x = Cell::new(1);\n",
    "  let y = &x;\n",
    "  let z = &x;\n",
    "  x.set(2);\n",
    "  y.set(3);\n",
    "  z.set(4);\n",
    "  println!(\"{}\", x.get());\n",
    "}"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [
    {
     "ename": "Error",
     "evalue": "cannot borrow `x` as mutable more than once at a time",
     "output_type": "error",
     "traceback": [
      "\u001b[31m[E0499] Error:\u001b[0m cannot borrow `x` as mutable more than once at a time",
      "   \u001b[38;5;246m╭\u001b[0m\u001b[38;5;246m─\u001b[0m\u001b[38;5;246m[\u001b[0m command_28:1:1 \u001b[38;5;246m]\u001b[0m",
      "   \u001b[38;5;246m│\u001b[0m",
      " \u001b[38;5;246m3 │\u001b[0m \u001b[38;5;249m \u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249ml\u001b[0m\u001b[38;5;249me\u001b[0m\u001b[38;5;249mt\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249my\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249m=\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;54m&\u001b[0m\u001b[38;5;54mm\u001b[0m\u001b[38;5;54mu\u001b[0m\u001b[38;5;54mt\u001b[0m\u001b[38;5;54m \u001b[0m\u001b[38;5;54mx\u001b[0m\u001b[38;5;249m;\u001b[0m",
      " \u001b[38;5;240m  │\u001b[0m           \u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m┬\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m  ",
      " \u001b[38;5;240m  │\u001b[0m              \u001b[38;5;54m╰\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m first mutable borrow occurs here",
      " \u001b[38;5;246m4 │\u001b[0m \u001b[38;5;249m \u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249ml\u001b[0m\u001b[38;5;249me\u001b[0m\u001b[38;5;249mt\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249mz\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249m=\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;100m&\u001b[0m\u001b[38;5;100mm\u001b[0m\u001b[38;5;100mu\u001b[0m\u001b[38;5;100mt\u001b[0m\u001b[38;5;100m \u001b[0m\u001b[38;5;100mx\u001b[0m\u001b[38;5;249m;\u001b[0m",
      " \u001b[38;5;240m  │\u001b[0m           \u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m┬\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m  ",
      " \u001b[38;5;240m  │\u001b[0m              \u001b[38;5;100m╰\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m second mutable borrow occurs here",
      " \u001b[38;5;240m  │\u001b[0m ",
      " \u001b[38;5;246m6 │\u001b[0m \u001b[38;5;249m \u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;68m*\u001b[0m\u001b[38;5;68my\u001b[0m\u001b[38;5;68m \u001b[0m\u001b[38;5;68m=\u001b[0m\u001b[38;5;68m \u001b[0m\u001b[38;5;68m3\u001b[0m\u001b[38;5;249m;\u001b[0m",
      " \u001b[38;5;240m  │\u001b[0m   \u001b[38;5;68m─\u001b[0m\u001b[38;5;68m─\u001b[0m\u001b[38;5;68m─\u001b[0m\u001b[38;5;68m┬\u001b[0m\u001b[38;5;68m─\u001b[0m\u001b[38;5;68m─\u001b[0m  ",
      " \u001b[38;5;240m  │\u001b[0m      \u001b[38;5;68m╰\u001b[0m\u001b[38;5;68m─\u001b[0m\u001b[38;5;68m─\u001b[0m\u001b[38;5;68m─\u001b[0m\u001b[38;5;68m─\u001b[0m first borrow later used here",
      "\u001b[38;5;246m───╯\u001b[0m"
     ]
    },
    {
     "ename": "Error",
     "evalue": "cannot assign to `x` because it is borrowed",
     "output_type": "error",
     "traceback": [
      "\u001b[31m[E0506] Error:\u001b[0m cannot assign to `x` because it is borrowed",
      "   \u001b[38;5;246m╭\u001b[0m\u001b[38;5;246m─\u001b[0m\u001b[38;5;246m[\u001b[0m command_28:1:1 \u001b[38;5;246m]\u001b[0m",
      "   \u001b[38;5;246m│\u001b[0m",
      " \u001b[38;5;246m3 │\u001b[0m \u001b[38;5;249m \u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249ml\u001b[0m\u001b[38;5;249me\u001b[0m\u001b[38;5;249mt\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249my\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249m=\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;54m&\u001b[0m\u001b[38;5;54mm\u001b[0m\u001b[38;5;54mu\u001b[0m\u001b[38;5;54mt\u001b[0m\u001b[38;5;54m \u001b[0m\u001b[38;5;54mx\u001b[0m\u001b[38;5;249m;\u001b[0m",
      " \u001b[38;5;240m  │\u001b[0m           \u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m┬\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m  ",
      " \u001b[38;5;240m  │\u001b[0m              \u001b[38;5;54m╰\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m `x` is borrowed here",
      " \u001b[38;5;240m  │\u001b[0m ",
      " \u001b[38;5;246m5 │\u001b[0m \u001b[38;5;249m \u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;100mx\u001b[0m\u001b[38;5;100m \u001b[0m\u001b[38;5;100m=\u001b[0m\u001b[38;5;100m \u001b[0m\u001b[38;5;100m2\u001b[0m\u001b[38;5;249m;\u001b[0m",
      " \u001b[38;5;240m  │\u001b[0m   \u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m┬\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m  ",
      " \u001b[38;5;240m  │\u001b[0m     \u001b[38;5;100m╰\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m `x` is assigned to here but it was already borrowed",
      " \u001b[38;5;246m6 │\u001b[0m \u001b[38;5;249m \u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;68m*\u001b[0m\u001b[38;5;68my\u001b[0m\u001b[38;5;68m \u001b[0m\u001b[38;5;68m=\u001b[0m\u001b[38;5;68m \u001b[0m\u001b[38;5;68m3\u001b[0m\u001b[38;5;249m;\u001b[0m",
      " \u001b[38;5;240m  │\u001b[0m   \u001b[38;5;68m─\u001b[0m\u001b[38;5;68m─\u001b[0m\u001b[38;5;68m─\u001b[0m\u001b[38;5;68m┬\u001b[0m\u001b[38;5;68m─\u001b[0m\u001b[38;5;68m─\u001b[0m  ",
      " \u001b[38;5;240m  │\u001b[0m      \u001b[38;5;68m╰\u001b[0m\u001b[38;5;68m─\u001b[0m\u001b[38;5;68m─\u001b[0m\u001b[38;5;68m─\u001b[0m\u001b[38;5;68m─\u001b[0m borrow later used here",
      "\u001b[38;5;246m───╯\u001b[0m"
     ]
    }
   ],
   "source": [
    "// code snipet 2\n",
    "\n",
    "{\n",
    "  let mut x = 1;\n",
    "  let y = &mut x;\n",
    "  let z = &mut x;\n",
    "  x = 2;\n",
    "  *y = 3;\n",
    "  *z = 4;\n",
    "  println!(\"{}\", x);\n",
    "}"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "虽然性能一致，但代码 `1` 拥有代码 `2` 不具有的优势：它能编译成功:)\n",
    "\n",
    "与 `Cell` 的 `zero cost` 不同，`RefCell` 其实是有一点运行期开销的，原因是它包含了一个字节大小的“借用状态”指示器，该指示器在每次运行时借用时都会被修改，进而产生一点开销。\n",
    "\n",
    "总之，当非要使用内部可变性时，首选 `Cell`，只有你的类型没有实现 `Copy` 时，才去选择 `RefCell`。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## [内部可变性](https://course.rs/advance/smart-pointer/cell-refcell.html#内部可变性)\n",
    "\n",
    "之前我们提到 `RefCell` 具有内部可变性，何为内部可变性？简单来说，对一个不可变的值进行可变借用，但这个并不符合 Rust 的基本借用规则："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 29,
   "metadata": {},
   "outputs": [
    {
     "ename": "Error",
     "evalue": "unused variable: `y`",
     "output_type": "error",
     "traceback": [
      "\u001b[31m[unused_variables] Error:\u001b[0m unused variable: `y`",
      "   \u001b[38;5;246m╭\u001b[0m\u001b[38;5;246m─\u001b[0m\u001b[38;5;246m[\u001b[0m command_29:1:1 \u001b[38;5;246m]\u001b[0m",
      "   \u001b[38;5;246m│\u001b[0m",
      " \u001b[38;5;246m3 │\u001b[0m \u001b[38;5;249m \u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249ml\u001b[0m\u001b[38;5;249me\u001b[0m\u001b[38;5;249mt\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;54my\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249m=\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249m&\u001b[0m\u001b[38;5;249mm\u001b[0m\u001b[38;5;249mu\u001b[0m\u001b[38;5;249mt\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249mx\u001b[0m\u001b[38;5;249m;\u001b[0m",
      " \u001b[38;5;240m  │\u001b[0m         \u001b[38;5;54m┬\u001b[0m  ",
      " \u001b[38;5;240m  │\u001b[0m         \u001b[38;5;54m╰\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m warning: unused variable: `y`",
      " \u001b[38;5;240m  │\u001b[0m         \u001b[38;5;100m│\u001b[0m  ",
      " \u001b[38;5;240m  │\u001b[0m         \u001b[38;5;100m╰\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m help: if this is intentional, prefix it with an underscore: `_y`",
      "\u001b[38;5;246m───╯\u001b[0m"
     ]
    },
    {
     "ename": "Error",
     "evalue": "cannot borrow `x` as mutable, as it is not declared as mutable",
     "output_type": "error",
     "traceback": [
      "\u001b[31m[E0596] Error:\u001b[0m cannot borrow `x` as mutable, as it is not declared as mutable",
      "   \u001b[38;5;246m╭\u001b[0m\u001b[38;5;246m─\u001b[0m\u001b[38;5;246m[\u001b[0m command_29:1:1 \u001b[38;5;246m]\u001b[0m",
      "   \u001b[38;5;246m│\u001b[0m",
      " \u001b[38;5;246m2 │\u001b[0m \u001b[38;5;249m \u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249ml\u001b[0m\u001b[38;5;249me\u001b[0m\u001b[38;5;249mt\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249mx\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249m=\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249m5\u001b[0m\u001b[38;5;249m;\u001b[0m",
      " \u001b[38;5;240m  │\u001b[0m         \u001b[38;5;100m│\u001b[0m ",
      " \u001b[38;5;240m  │\u001b[0m         \u001b[38;5;100m╰\u001b[0m\u001b[38;5;100m─\u001b[0m help: consider changing this to be mutable: `mut `",
      " \u001b[38;5;246m3 │\u001b[0m \u001b[38;5;249m \u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249ml\u001b[0m\u001b[38;5;249me\u001b[0m\u001b[38;5;249mt\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249my\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249m=\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;54m&\u001b[0m\u001b[38;5;54mm\u001b[0m\u001b[38;5;54mu\u001b[0m\u001b[38;5;54mt\u001b[0m\u001b[38;5;54m \u001b[0m\u001b[38;5;54mx\u001b[0m\u001b[38;5;249m;\u001b[0m",
      " \u001b[38;5;240m  │\u001b[0m             \u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m┬\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m  ",
      " \u001b[38;5;240m  │\u001b[0m                \u001b[38;5;54m╰\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m cannot borrow as mutable",
      " \u001b[38;5;240m  │\u001b[0m ",
      " \u001b[38;5;240m  │\u001b[0m \u001b[38;5;115mNote\u001b[0m: You can change an existing variable to mutable like: `let mut x = x;`",
      "\u001b[38;5;246m───╯\u001b[0m"
     ]
    }
   ],
   "source": [
    "{\n",
    "    let x = 5;\n",
    "    let y = &mut x;\n",
    "}"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "上面的代码会报错，因为我们不能对一个不可变的值进行可变借用，这会破坏 Rust 的安全性保证，相反，你可以对一个可变值进行不可变借用。原因是：当值不可变时，可能会有多个不可变的引用指向它，此时若将其中一个修改为可变的，会造成可变引用与不可变引用共存的情况；而当值可变时，最多只会有一个可变引用指向它，将其修改为不可变，那么最终依然是只有一个不可变的引用指向它。\n",
    "\n",
    "虽然基本借用规则是 Rust 的基石，然而在某些场景中，一个值可以在其方法内部被修改，同时对于其它代码不可变，是很有用的："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [
    {
     "ename": "Error",
     "evalue": "cannot borrow `self.msg_cache` as mutable, as it is behind a `&` reference",
     "output_type": "error",
     "traceback": [
      "\u001b[31m[E0596] Error:\u001b[0m cannot borrow `self.msg_cache` as mutable, as it is behind a `&` reference",
      "    \u001b[38;5;246m╭\u001b[0m\u001b[38;5;246m─\u001b[0m\u001b[38;5;246m[\u001b[0m command_31:1:1 \u001b[38;5;246m]\u001b[0m",
      "    \u001b[38;5;246m│\u001b[0m",
      " \u001b[38;5;246m11 │\u001b[0m \u001b[38;5;249m \u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;54ms\u001b[0m\u001b[38;5;54me\u001b[0m\u001b[38;5;54ml\u001b[0m\u001b[38;5;54mf\u001b[0m\u001b[38;5;54m.\u001b[0m\u001b[38;5;54mm\u001b[0m\u001b[38;5;54ms\u001b[0m\u001b[38;5;54mg\u001b[0m\u001b[38;5;54m_\u001b[0m\u001b[38;5;54mc\u001b[0m\u001b[38;5;54ma\u001b[0m\u001b[38;5;54mc\u001b[0m\u001b[38;5;54mh\u001b[0m\u001b[38;5;54me\u001b[0m\u001b[38;5;249m.\u001b[0m\u001b[38;5;249mp\u001b[0m\u001b[38;5;249mu\u001b[0m\u001b[38;5;249ms\u001b[0m\u001b[38;5;249mh\u001b[0m\u001b[38;5;249m(\u001b[0m\u001b[38;5;249mm\u001b[0m\u001b[38;5;249ms\u001b[0m\u001b[38;5;249mg\u001b[0m\u001b[38;5;249m)\u001b[0m",
      " \u001b[38;5;240m   │\u001b[0m         \u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m┬\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m  ",
      " \u001b[38;5;240m   │\u001b[0m                \u001b[38;5;54m╰\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m `self` is a `&` reference, so the data it refers to cannot be borrowed as mutable",
      " \u001b[38;5;240m   │\u001b[0m ",
      " \u001b[38;5;240m   │\u001b[0m \u001b[38;5;115mNote\u001b[0m: You can change an existing variable to mutable like: `let mut x = x;`",
      "\u001b[38;5;246m────╯\u001b[0m"
     ]
    }
   ],
   "source": [
    "// 定义在外部库中的特征\n",
    "pub trait Messenger {\n",
    "    fn send(&self, msg: String);\n",
    "}\n",
    "\n",
    "// --------------------------\n",
    "// 我们的代码中的数据结构和实现\n",
    "struct MsgQueue {\n",
    "    msg_cache: Vec<String>,\n",
    "}\n",
    "\n",
    "impl Messenger for MsgQueue {\n",
    "    fn send(&self, msg: String) {\n",
    "        self.msg_cache.push(msg)\n",
    "    }\n",
    "}"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "如上所示，外部库中定义了一个消息发送器特征 `Messenger`，它只有一个发送消息的功能：`fn send(&self, msg: String)`，因为发送消息不需要修改自身，因此原作者在定义时，使用了 `&self` 的不可变借用，这个无可厚非。\n",
    "\n",
    "我们要在自己的代码中使用该特征实现一个异步消息队列，出于性能的考虑，消息先写到本地缓存(内存)中，然后批量发送出去，因此在 `send` 方法中，需要将消息先行插入到本地缓存 `msg_cache` 中。但是问题来了，该 `send` 方法的签名是 `&self`，因此上述代码会报错：\n",
    "\n",
    "在报错的同时，编译器大聪明还善意地给出了提示：将 `&self` 修改为 `&mut self`，但是。。。我们实现的特征是定义在外部库中，因此该签名根本不能修改。值此危急关头， `RefCell` 闪亮登场："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 32,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "()"
      ]
     },
     "execution_count": 32,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "use std::cell::RefCell;\n",
    "\n",
    "pub trait Messenger {\n",
    "    fn send(&self, msg: String);\n",
    "}\n",
    "\n",
    "pub struct MsgQueue {\n",
    "    msg_cache: RefCell<Vec<String>>,\n",
    "}\n",
    "\n",
    "impl Messenger for MsgQueue {\n",
    "    fn send(&self, msg: String) {\n",
    "        self.msg_cache.borrow_mut().push(msg)\n",
    "    }\n",
    "}\n",
    "\n",
    "{\n",
    "    let mq = MsgQueue {\n",
    "        msg_cache: RefCell::new(Vec::new()),\n",
    "    };\n",
    "    mq.send(\"hello, world\".to_string());\n",
    "}"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "这个 MQ 功能很弱，但是并不妨碍我们演示内部可变性的核心用法：通过包裹一层 `RefCell`，成功的让 `&self` 中的 `msg_cache` 成为一个可变值，然后实现对其的修改。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## [Rc + RefCell 组合使用](https://course.rs/advance/smart-pointer/cell-refcell.html#rc--refcell-组合使用)\n",
    "\n",
    "在 Rust 中，一个常见的组合就是 `Rc` 和 `RefCell` 在一起使用，前者可以实现一个数据拥有多个所有者，后者可以实现数据的可变性："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 33,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "RefCell { value: \"我很善变，还拥有多个主人, oh yeah!\" }\n",
      "RefCell { value: \"我很善变，还拥有多个主人, oh yeah!\" }\n",
      "RefCell { value: \"我很善变，还拥有多个主人, oh yeah!\" }\n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "()"
      ]
     },
     "execution_count": 33,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "use std::cell::RefCell;\n",
    "use std::rc::Rc;\n",
    "\n",
    "{\n",
    "    let s = Rc::new(RefCell::new(\"我很善变，还拥有多个主人\".to_string()));\n",
    "\n",
    "    let s1 = s.clone();\n",
    "    let s2 = s.clone();\n",
    "    // let mut s2 = s.borrow_mut();\n",
    "    s2.borrow_mut().push_str(\", oh yeah!\");\n",
    "\n",
    "    println!(\"{:?}\\n{:?}\\n{:?}\", s, s1, s2);\n",
    "}"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "上面代码中，我们使用 `RefCell<String>` 包裹一个字符串，同时通过 `Rc` 创建了它的三个所有者：`s`、`s1`和`s2`，并且通过其中一个所有者 `s2` 对字符串内容进行了修改。\n",
    "\n",
    "由于 `Rc` 的所有者们共享同一个底层的数据，因此当一个所有者修改了数据时，会导致全部所有者持有的数据都发生了变化。\n",
    "\n",
    "程序的运行结果也在预料之中："
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### [性能损耗](https://course.rs/advance/smart-pointer/cell-refcell.html#性能损耗)\n",
    "\n",
    "相信这两者组合在一起使用时，很多人会好奇到底性能如何，下面我们来简单分析下。\n",
    "\n",
    "首先给出一个大概的结论，这两者结合在一起使用的性能其实非常高，大致相当于没有线程安全版本的 C++ `std::shared_ptr` 指针，事实上，C++ 这个指针的主要开销也在于原子性这个并发原语上，毕竟线程安全在哪个语言中开销都不小。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### [内存损耗](https://course.rs/advance/smart-pointer/cell-refcell.html#内存损耗)\n",
    "\n",
    "两者结合的数据结构与下面类似："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "struct Wrapper<T> {\n",
    "    // Rc\n",
    "    strong_count: usize,\n",
    "    weak_count: usize,\n",
    "\n",
    "    // Refcell\n",
    "    borrow_count: isize,\n",
    "\n",
    "    // 包裹的数据\n",
    "    item: T,\n",
    "}"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "从上面可以看出，从对内存的影响来看，仅仅多分配了三个`usize/isize`，并没有其它额外的负担。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### [CPU 损耗](https://course.rs/advance/smart-pointer/cell-refcell.html#cpu-损耗)\n",
    "\n",
    "从 CPU 来看，损耗如下：\n",
    "\n",
    "- 对 `Rc<T>` 解引用是免费的（编译期），但是 `*` 带来的间接取值并不免费\n",
    "- 克隆 `Rc<T>` 需要将当前的引用计数跟 `0` 和 `usize::Max` 进行一次比较，然后将计数值加 1\n",
    "- 释放（drop） `Rc<T>` 需要将计数值减 1， 然后跟 `0` 进行一次比较\n",
    "- 对 `RefCell` 进行不可变借用，需要将 `isize` 类型的借用计数加 1，然后跟 `0` 进行比较\n",
    "- 对 `RefCell `的不可变借用进行释放，需要将 `isize` 减 1\n",
    "- 对 `RefCell` 的可变借用大致流程跟上面差不多，但是需要先跟 `0` 比较，然后再减 1\n",
    "- 对 `RefCell` 的可变借用进行释放，需要将 `isize` 加 1\n",
    "\n",
    "其实这些细节不必过于关注，只要知道 CPU 消耗也非常低，甚至编译器还会对此进行进一步优化！"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### [CPU 缓存 Miss](https://course.rs/advance/smart-pointer/cell-refcell.html#cpu-缓存-miss)\n",
    "\n",
    "唯一需要担心的可能就是这种组合数据结构对于 CPU 缓存是否亲和，这个我们无法证明，只能提出来存在这个可能性，最终的性能影响还需要在实际场景中进行测试。\n",
    "\n",
    "总之，分析这两者组合的性能还挺复杂的，大概总结下：\n",
    "\n",
    "- 从表面来看，它们带来的内存和 CPU 损耗都不大\n",
    "- 但是由于 `Rc` 额外的引入了一次间接取值（`*`），在少数场景下可能会造成性能上的显著损失\n",
    "- CPU 缓存可能也不够亲和"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## [通过 `Cell::from_mut` 解决借用冲突](https://course.rs/advance/smart-pointer/cell-refcell.html#通过-cellfrom_mut-解决借用冲突)\n",
    "\n",
    "在 Rust 1.37 版本中新增了两个非常实用的方法：\n",
    "\n",
    "- `Cell::from_mut`，该方法将 `&mut T` 转为 `&Cell<T>`\n",
    "-`Cell::as_slice_of_cells`，该方法将 `&Cell<[T]>` 转为 `&[Cell<T>]`\n",
    "\n",
    "这里我们不做深入的介绍，但是来看看如何使用这两个方法来解决一个常见的借用冲突问题："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 34,
   "metadata": {},
   "outputs": [
    {
     "ename": "Error",
     "evalue": "cannot borrow `*nums` as mutable because it is also borrowed as immutable",
     "output_type": "error",
     "traceback": [
      "\u001b[31m[E0502] Error:\u001b[0m cannot borrow `*nums` as mutable because it is also borrowed as immutable",
      "   \u001b[38;5;246m╭\u001b[0m\u001b[38;5;246m─\u001b[0m\u001b[38;5;246m[\u001b[0m command_34:1:1 \u001b[38;5;246m]\u001b[0m",
      "   \u001b[38;5;246m│\u001b[0m",
      " \u001b[38;5;246m7 │\u001b[0m \u001b[38;5;249m \u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249mf\u001b[0m\u001b[38;5;249mo\u001b[0m\u001b[38;5;249mr\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249mn\u001b[0m\u001b[38;5;249mu\u001b[0m\u001b[38;5;249mm\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249mi\u001b[0m\u001b[38;5;249mn\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;100mn\u001b[0m\u001b[38;5;100mu\u001b[0m\u001b[38;5;100mm\u001b[0m\u001b[38;5;100ms\u001b[0m\u001b[38;5;68m.\u001b[0m\u001b[38;5;68mi\u001b[0m\u001b[38;5;68mt\u001b[0m\u001b[38;5;68me\u001b[0m\u001b[38;5;68mr\u001b[0m\u001b[38;5;68m(\u001b[0m\u001b[38;5;68m)\u001b[0m\u001b[38;5;68m.\u001b[0m\u001b[38;5;68mf\u001b[0m\u001b[38;5;68mi\u001b[0m\u001b[38;5;68ml\u001b[0m\u001b[38;5;68mt\u001b[0m\u001b[38;5;68me\u001b[0m\u001b[38;5;68mr\u001b[0m\u001b[38;5;68m(\u001b[0m\u001b[38;5;68m|\u001b[0m\u001b[38;5;68m&\u001b[0m\u001b[38;5;68mn\u001b[0m\u001b[38;5;68mu\u001b[0m\u001b[38;5;68mm\u001b[0m\u001b[38;5;68m|\u001b[0m\u001b[38;5;68m \u001b[0m\u001b[38;5;68mi\u001b[0m\u001b[38;5;68ms\u001b[0m\u001b[38;5;68m_\u001b[0m\u001b[38;5;68me\u001b[0m\u001b[38;5;68mv\u001b[0m\u001b[38;5;68me\u001b[0m\u001b[38;5;68mn\u001b[0m\u001b[38;5;68m(\u001b[0m\u001b[38;5;68m*\u001b[0m\u001b[38;5;68mn\u001b[0m\u001b[38;5;68mu\u001b[0m\u001b[38;5;68mm\u001b[0m\u001b[38;5;68m)\u001b[0m\u001b[38;5;68m)\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249m{\u001b[0m",
      " \u001b[38;5;240m  │\u001b[0m                \u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m┬\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;68m─\u001b[0m\u001b[38;5;68m─\u001b[0m\u001b[38;5;68m─\u001b[0m\u001b[38;5;68m─\u001b[0m\u001b[38;5;68m─\u001b[0m\u001b[38;5;68m─\u001b[0m\u001b[38;5;68m─\u001b[0m\u001b[38;5;68m─\u001b[0m\u001b[38;5;68m─\u001b[0m\u001b[38;5;68m─\u001b[0m\u001b[38;5;68m─\u001b[0m\u001b[38;5;68m─\u001b[0m\u001b[38;5;68m─\u001b[0m\u001b[38;5;68m─\u001b[0m\u001b[38;5;68m─\u001b[0m\u001b[38;5;68m─\u001b[0m\u001b[38;5;68m┬\u001b[0m\u001b[38;5;68m─\u001b[0m\u001b[38;5;68m─\u001b[0m\u001b[38;5;68m─\u001b[0m\u001b[38;5;68m─\u001b[0m\u001b[38;5;68m─\u001b[0m\u001b[38;5;68m─\u001b[0m\u001b[38;5;68m─\u001b[0m\u001b[38;5;68m─\u001b[0m\u001b[38;5;68m─\u001b[0m\u001b[38;5;68m─\u001b[0m\u001b[38;5;68m─\u001b[0m\u001b[38;5;68m─\u001b[0m\u001b[38;5;68m─\u001b[0m\u001b[38;5;68m─\u001b[0m\u001b[38;5;68m─\u001b[0m\u001b[38;5;68m─\u001b[0m\u001b[38;5;68m─\u001b[0m\u001b[38;5;68m─\u001b[0m\u001b[38;5;68m─\u001b[0m  ",
      " \u001b[38;5;240m  │\u001b[0m                  \u001b[38;5;100m╰\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m immutable borrow occurs here",
      " \u001b[38;5;240m  │\u001b[0m                                    \u001b[38;5;68m│\u001b[0m                     ",
      " \u001b[38;5;240m  │\u001b[0m                                    \u001b[38;5;68m╰\u001b[0m\u001b[38;5;68m─\u001b[0m\u001b[38;5;68m─\u001b[0m\u001b[38;5;68m─\u001b[0m\u001b[38;5;68m─\u001b[0m\u001b[38;5;68m─\u001b[0m\u001b[38;5;68m─\u001b[0m\u001b[38;5;68m─\u001b[0m\u001b[38;5;68m─\u001b[0m\u001b[38;5;68m─\u001b[0m\u001b[38;5;68m─\u001b[0m\u001b[38;5;68m─\u001b[0m\u001b[38;5;68m─\u001b[0m\u001b[38;5;68m─\u001b[0m\u001b[38;5;68m─\u001b[0m\u001b[38;5;68m─\u001b[0m\u001b[38;5;68m─\u001b[0m\u001b[38;5;68m─\u001b[0m\u001b[38;5;68m─\u001b[0m\u001b[38;5;68m─\u001b[0m\u001b[38;5;68m─\u001b[0m\u001b[38;5;68m─\u001b[0m immutable borrow later used here",
      " \u001b[38;5;246m8 │\u001b[0m \u001b[38;5;249m \u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;54mn\u001b[0m\u001b[38;5;54mu\u001b[0m\u001b[38;5;54mm\u001b[0m\u001b[38;5;54ms\u001b[0m\u001b[38;5;249m[\u001b[0m\u001b[38;5;249mi\u001b[0m\u001b[38;5;249m]\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249m=\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249m*\u001b[0m\u001b[38;5;249mn\u001b[0m\u001b[38;5;249mu\u001b[0m\u001b[38;5;249mm\u001b[0m\u001b[38;5;249m;\u001b[0m",
      " \u001b[38;5;240m  │\u001b[0m         \u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m┬\u001b[0m\u001b[38;5;54m─\u001b[0m  ",
      " \u001b[38;5;240m  │\u001b[0m           \u001b[38;5;54m╰\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m mutable borrow occurs here",
      "\u001b[38;5;246m───╯\u001b[0m"
     ]
    }
   ],
   "source": [
    "fn is_even(i: i32) -> bool {\n",
    "    i % 2 == 0\n",
    "}\n",
    "\n",
    "fn retain_even(nums: &mut Vec<i32>) {\n",
    "    let mut i = 0;\n",
    "    for num in nums.iter().filter(|&num| is_even(*num)) {\n",
    "        nums[i] = *num;\n",
    "        i += 1;\n",
    "    }\n",
    "    nums.truncate(i);\n",
    "}"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "很明显，报错是因为同时借用了不可变与可变引用，你可以通过索引的方式来避免这个问题："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 36,
   "metadata": {},
   "outputs": [],
   "source": [
    "fn is_even(i: i32) -> bool {\n",
    "    i % 2 == 0\n",
    "}\n",
    "\n",
    "fn retain_even(nums: &mut Vec<i32>) {\n",
    "    let mut i = 0;\n",
    "    for j in 0..nums.len() {\n",
    "        if is_even(nums[j]) {\n",
    "            nums[i] = nums[j];\n",
    "            i += 1;\n",
    "        }\n",
    "    }\n",
    "    nums.truncate(i);\n",
    "}"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "但是这样就违背我们的初衷了，毕竟迭代器会让代码更加简洁，那么还有其它的办法吗？\n",
    "\n",
    "这时就可以使用 `Cell` 新增的这两个方法："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 37,
   "metadata": {},
   "outputs": [],
   "source": [
    "use std::cell::Cell;\n",
    "\n",
    "fn retain_even(nums: &mut Vec<i32>) {\n",
    "    let slice: &[Cell<i32>] = Cell::from_mut(&mut nums[..])\n",
    "        .as_slice_of_cells();\n",
    "\n",
    "    let mut i = 0;\n",
    "    for num in slice.iter().filter(|num| is_even(num.get())) {\n",
    "        slice[i].set(num.get());\n",
    "        i += 1;\n",
    "    }\n",
    "\n",
    "    nums.truncate(i);\n",
    "}"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "此时代码将不会报错，因为 `Cell` 上的 `set` 方法获取的是不可变引用 `pub fn set(&self, val: T)`。\n",
    "\n",
    "当然，以上代码的本质还是对 `Cell` 的运用，只不过这两个方法可以很方便的帮我们把 `&mut [T]` 类型转换成 `&[Cell<T>]` 类型。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## [总结](https://course.rs/advance/smart-pointer/cell-refcell.html#总结)\n",
    "\n",
    "`Cell` 和 `RefCell` 都为我们带来了内部可变性这个重要特性，同时还将借用规则的检查从编译期推迟到运行期，但是这个检查并不能被绕过，该来早晚还是会来，`RefCell` 在运行期的报错会造成 `panic`。\n",
    "\n",
    "`RefCell` 适用于编译器误报或者一个引用被在多个代码中使用、修改以至于难于管理借用关系时，还有就是需要内部可变性时。\n",
    "\n",
    "从性能上看，`RefCell` 由于是非线程安全的，因此无需保证原子性，性能虽然有一点损耗，但是依然非常好，而 `Cell` 则完全不存在任何额外的性能损耗。\n",
    "\n",
    "`Rc` 跟 `RefCell` 结合使用可以实现多个所有者共享同一份数据，非常好用，但是潜在的性能损耗也要考虑进去，建议对于热点代码使用时，做好 `benchmark`。"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Rust",
   "language": "rust",
   "name": "rust"
  },
  "language_info": {
   "codemirror_mode": "rust",
   "file_extension": ".rs",
   "mimetype": "text/rust",
   "name": "rust",
   "pygment_lexer": "rust",
   "version": ""
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
